root/src/cmd/yacc/expr.y

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. import
  2. func
  3. func
  4. func
  5. func
  6. main

// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This is an example of a goyacc program.
// To build it:
// go tool yacc -p "expr" expr.y (produces y.go)
// go build -o expr y.go
// expr
// > <type an expression>

%{

// This tag will be copied to the generated file to prevent that file
// confusing a future build.

// +build ignore

package main

import (
        "bufio"
        "bytes"
        "fmt"
        "io"
        "log"
        "math/big"
        "os"
        "unicode/utf8"
)

%}

%union {
        num *big.Rat
}

%type   <num>   expr expr1 expr2 expr3

%token  <num>   NUM

%%

top:
        expr
        {
                if $1.IsInt() {
                        fmt.Println($1.Num().String())
                } else {
                        fmt.Println($1.String())
                }
        }

expr:
        expr1
|       '+' expr
        {
                $$ = $2
        }
|       '-' expr
        {
                $$.Neg($2)
        }

expr1:
        expr2
|       expr1 '+' expr2
        {
                $$.Add($1, $3)
        }
|       expr1 '-' expr2
        {
                $$.Sub($1, $3)
        }

expr2:
        expr3
|       expr2 '*' expr3
        {
                $$.Mul($1, $3)
        }
|       expr2 '/' expr3
        {
                $$.Quo($1, $3)
        }

expr3:
        NUM
|       '(' expr ')'
        {
                $$ = $2
        }


%%

// The parser expects the lexer to return 0 on EOF.  Give it a name
// for clarity.
const eof = 0

// The parser uses the type <prefix>Lex as a lexer.  It must provide
// the methods Lex(*<prefix>SymType) int and Error(string).
type exprLex struct {
        line []byte
        peek rune
}

// The parser calls this method to get each new token.  This
// implementation returns operators and NUM.
func (x *exprLex) Lex(yylval *exprSymType) int {
        for {
                c := x.next()
                switch c {
                case eof:
                        return eof
                case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
                        return x.num(c, yylval)
                case '+', '-', '*', '/', '(', ')':
                        return int(c)

                // Recognize Unicode multiplication and division
                // symbols, returning what the parser expects.
                case '×':
                        return '*'
                case '÷':
                        return '/'

                case ' ', '\t', '\n', '\r':
                default:
                        log.Printf("unrecognized character %q", c)
                }
        }
}

// Lex a number.
func (x *exprLex) num(c rune, yylval *exprSymType) int {
        add := func(b *bytes.Buffer, c rune) {
                if _, err := b.WriteRune(c); err != nil {
                        log.Fatalf("WriteRune: %s", err)
                }
        }
        var b bytes.Buffer
        add(&b, c)
        L: for {
                c = x.next()
                switch c {
                case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E':
                        add(&b, c)
                default:
                        break L
                }
        }
        if c != eof {
                x.peek = c
        }
        yylval.num = &big.Rat{}
        _, ok := yylval.num.SetString(b.String())
        if !ok {
                log.Printf("bad number %q", b.String())
                return eof
        }
        return NUM
}

// Return the next rune for the lexer.
func (x *exprLex) next() rune {
        if x.peek != eof {
                r := x.peek
                x.peek = eof
                return r
        }
        if len(x.line) == 0 {
                return eof
        }
        c, size := utf8.DecodeRune(x.line)
        x.line = x.line[size:]
        if c == utf8.RuneError && size == 1 {
                log.Print("invalid utf8")
                return x.next()
        }
        return c
}

// The parser calls this method on a parse error.
func (x *exprLex) Error(s string) {
        log.Printf("parse error: %s", s)
}

func main() {
        in := bufio.NewReader(os.Stdin)
        for {
                if _, err := os.Stdout.WriteString("> "); err != nil {
                        log.Fatalf("WriteString: %s", err)
                }
                line, err := in.ReadBytes('\n')
                if err == io.EOF {
                        return
                }
                if err != nil {
                        log.Fatalf("ReadBytes: %s", err)
                }

                exprParse(&exprLex{line: line})
        }
}

/* [<][>][^][v][top][bottom][index][help] */