github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/cmd/goyacc/testdata/expr/expr.y (about)

     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  
    14  package main
    15  
    16  import (
    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  
    41  top:
    42  	expr
    43  	{
    44  		if $1.IsInt() {
    45  			fmt.Println($1.Num().String())
    46  		} else {
    47  			fmt.Println($1.String())
    48  		}
    49  	}
    50  
    51  expr:
    52  	expr1
    53  |	'+' expr
    54  	{
    55  		$$ = $2
    56  	}
    57  |	'-' expr
    58  	{
    59  		$$ = $2.Neg($2)
    60  	}
    61  
    62  expr1:
    63  	expr2
    64  |	expr1 '+' expr2
    65  	{
    66  		$$ = $1.Add($1, $3)
    67  	}
    68  |	expr1 '-' expr2
    69  	{
    70  		$$ = $1.Sub($1, $3)
    71  	}
    72  
    73  expr2:
    74  	expr3
    75  |	expr2 '*' expr3
    76  	{
    77  		$$ = $1.Mul($1, $3)
    78  	}
    79  |	expr2 '/' expr3
    80  	{
    81  		$$ = $1.Quo($1, $3)
    82  	}
    83  
    84  expr3:
    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.
    96  const 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).
   100  type 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.
   107  func (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.
   133  func (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.
   163  func (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.
   182  func (x *exprLex) Error(s string) {
   183  	log.Printf("parse error: %s", s)
   184  }
   185  
   186  func 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  }