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