mirror of
https://github.com/golang/go
synced 2024-11-18 15:14:44 -07:00
f1ba7e38e5
This moves the 'go tool yacc' command from the main Go repo
to x/tools.
Copied from go rev 795ad07b3
+ doc changes from "go tool yacc" to "goyacc".
Updates golang/go#11229
Change-Id: I6d17911a3bf64724c090c4fe4903238e3bce3b8c
Reviewed-on: https://go-review.googlesource.com/27324
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
203 lines
3.1 KiB
Plaintext
203 lines
3.1 KiB
Plaintext
// 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:
|
||
// goyacc -p "expr" expr.y (produces y.go)
|
||
// go build -o expr y.go
|
||
// expr
|
||
// > <type an expression>
|
||
|
||
%{
|
||
|
||
package main
|
||
|
||
import (
|
||
"bufio"
|
||
"bytes"
|
||
"fmt"
|
||
"io"
|
||
"log"
|
||
"math/big"
|
||
"os"
|
||
"unicode/utf8"
|
||
)
|
||
|
||
%}
|
||
|
||
%union {
|
||
num *big.Rat
|
||
}
|
||
|
||
%type <num> expr expr1 expr2 expr3
|
||
|
||
%token '+' '-' '*' '/' '(' ')'
|
||
|
||
%token <num> NUM
|
||
|
||
%%
|
||
|
||
top:
|
||
expr
|
||
{
|
||
if $1.IsInt() {
|
||
fmt.Println($1.Num().String())
|
||
} else {
|
||
fmt.Println($1.String())
|
||
}
|
||
}
|
||
|
||
expr:
|
||
expr1
|
||
| '+' expr
|
||
{
|
||
$$ = $2
|
||
}
|
||
| '-' expr
|
||
{
|
||
$$ = $2.Neg($2)
|
||
}
|
||
|
||
expr1:
|
||
expr2
|
||
| expr1 '+' expr2
|
||
{
|
||
$$ = $1.Add($1, $3)
|
||
}
|
||
| expr1 '-' expr2
|
||
{
|
||
$$ = $1.Sub($1, $3)
|
||
}
|
||
|
||
expr2:
|
||
expr3
|
||
| expr2 '*' expr3
|
||
{
|
||
$$ = $1.Mul($1, $3)
|
||
}
|
||
| expr2 '/' expr3
|
||
{
|
||
$$ = $1.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})
|
||
}
|
||
}
|