...

Text file src/golang.org/x/tools/cmd/goyacc/testdata/expr/expr.y

Documentation: golang.org/x/tools/cmd/goyacc/testdata/expr

     1// Copyright 2013 The Go Authors. All rights reserved.
     2// Use of this source code is governed by a BSD-style
     3// license that can be found in the LICENSE file.
     4
     5// This is an example of a goyacc program.
     6// To build it:
     7// goyacc -p "expr" expr.y (produces y.go)
     8// go build -o expr y.go
     9// expr
    10// > <type an expression>
    11
    12%{
    13
    14package main
    15
    16import (
    17	"bufio"
    18	"bytes"
    19	"fmt"
    20	"io"
    21	"log"
    22	"math/big"
    23	"os"
    24	"unicode/utf8"
    25)
    26
    27%}
    28
    29%union {
    30	num *big.Rat
    31}
    32
    33%type	<num>	expr expr1 expr2 expr3
    34
    35%token '+' '-' '*' '/' '(' ')'
    36
    37%token	<num>	NUM
    38
    39%%
    40
    41top:
    42	expr
    43	{
    44		if $1.IsInt() {
    45			fmt.Println($1.Num().String())
    46		} else {
    47			fmt.Println($1.String())
    48		}
    49	}
    50
    51expr:
    52	expr1
    53|	'+' expr
    54	{
    55		$$ = $2
    56	}
    57|	'-' expr
    58	{
    59		$$ = $2.Neg($2)
    60	}
    61
    62expr1:
    63	expr2
    64|	expr1 '+' expr2
    65	{
    66		$$ = $1.Add($1, $3)
    67	}
    68|	expr1 '-' expr2
    69	{
    70		$$ = $1.Sub($1, $3)
    71	}
    72
    73expr2:
    74	expr3
    75|	expr2 '*' expr3
    76	{
    77		$$ = $1.Mul($1, $3)
    78	}
    79|	expr2 '/' expr3
    80	{
    81		$$ = $1.Quo($1, $3)
    82	}
    83
    84expr3:
    85	NUM
    86|	'(' expr ')'
    87	{
    88		$$ = $2
    89	}
    90
    91
    92%%
    93
    94// The parser expects the lexer to return 0 on EOF.  Give it a name
    95// for clarity.
    96const eof = 0
    97
    98// The parser uses the type <prefix>Lex as a lexer. It must provide
    99// the methods Lex(*<prefix>SymType) int and Error(string).
   100type exprLex struct {
   101	line []byte
   102	peek rune
   103}
   104
   105// The parser calls this method to get each new token. This
   106// implementation returns operators and NUM.
   107func (x *exprLex) Lex(yylval *exprSymType) int {
   108	for {
   109		c := x.next()
   110		switch c {
   111		case eof:
   112			return eof
   113		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
   114			return x.num(c, yylval)
   115		case '+', '-', '*', '/', '(', ')':
   116			return int(c)
   117
   118		// Recognize Unicode multiplication and division
   119		// symbols, returning what the parser expects.
   120		case '×':
   121			return '*'
   122		case '÷':
   123			return '/'
   124
   125		case ' ', '\t', '\n', '\r':
   126		default:
   127			log.Printf("unrecognized character %q", c)
   128		}
   129	}
   130}
   131
   132// Lex a number.
   133func (x *exprLex) num(c rune, yylval *exprSymType) int {
   134	add := func(b *bytes.Buffer, c rune) {
   135		if _, err := b.WriteRune(c); err != nil {
   136			log.Fatalf("WriteRune: %s", err)
   137		}
   138	}
   139	var b bytes.Buffer
   140	add(&b, c)
   141	L: for {
   142		c = x.next()
   143		switch c {
   144		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E':
   145			add(&b, c)
   146		default:
   147			break L
   148		}
   149	}
   150	if c != eof {
   151		x.peek = c
   152	}
   153	yylval.num = &big.Rat{}
   154	_, ok := yylval.num.SetString(b.String())
   155	if !ok {
   156		log.Printf("bad number %q", b.String())
   157		return eof
   158	}
   159	return NUM
   160}
   161
   162// Return the next rune for the lexer.
   163func (x *exprLex) next() rune {
   164	if x.peek != eof {
   165		r := x.peek
   166		x.peek = eof
   167		return r
   168	}
   169	if len(x.line) == 0 {
   170		return eof
   171	}
   172	c, size := utf8.DecodeRune(x.line)
   173	x.line = x.line[size:]
   174	if c == utf8.RuneError && size == 1 {
   175		log.Print("invalid utf8")
   176		return x.next()
   177	}
   178	return c
   179}
   180
   181// The parser calls this method on a parse error.
   182func (x *exprLex) Error(s string) {
   183	log.Printf("parse error: %s", s)
   184}
   185
   186func main() {
   187	in := bufio.NewReader(os.Stdin)
   188	for {
   189		if _, err := os.Stdout.WriteString("> "); err != nil {
   190			log.Fatalf("WriteString: %s", err)
   191		}
   192		line, err := in.ReadBytes('\n')
   193		if err == io.EOF {
   194			return
   195		}
   196		if err != nil {
   197			log.Fatalf("ReadBytes: %s", err)
   198		}
   199
   200		exprParse(&exprLex{line: line})
   201	}
   202}

View as plain text