mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
cmd/goyacc: move go tool yacc from the go repo
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>
This commit is contained in:
parent
1cf0a337cd
commit
f1ba7e38e5
70
cmd/goyacc/doc.go
Normal file
70
cmd/goyacc/doc.go
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
/*
|
||||
|
||||
Goyacc is a version of yacc for Go.
|
||||
It is written in Go and generates parsers written in Go.
|
||||
|
||||
Usage:
|
||||
|
||||
goyacc args...
|
||||
|
||||
It is largely transliterated from the Inferno version written in Limbo
|
||||
which in turn was largely transliterated from the Plan 9 version
|
||||
written in C and documented at
|
||||
|
||||
https://9p.io/magic/man2html/1/yacc
|
||||
|
||||
Adepts of the original yacc will have no trouble adapting to this
|
||||
form of the tool.
|
||||
|
||||
The directory $GOPATH/src/golang.org/x/tools/cmd/goyacc/testdata/expr
|
||||
is a yacc program for a very simple expression parser. See expr.y and
|
||||
main.go in that directory for examples of how to write and build
|
||||
goyacc programs.
|
||||
|
||||
The generated parser is reentrant. The parsing function yyParse expects
|
||||
to be given an argument that conforms to the following interface:
|
||||
|
||||
type yyLexer interface {
|
||||
Lex(lval *yySymType) int
|
||||
Error(e string)
|
||||
}
|
||||
|
||||
Lex should return the token identifier, and place other token
|
||||
information in lval (which replaces the usual yylval).
|
||||
Error is equivalent to yyerror in the original yacc.
|
||||
|
||||
Code inside the grammar actions may refer to the variable yylex,
|
||||
which holds the yyLexer passed to yyParse.
|
||||
|
||||
Clients that need to understand more about the parser state can
|
||||
create the parser separately from invoking it. The function yyNewParser
|
||||
returns a yyParser conforming to the following interface:
|
||||
|
||||
type yyParser interface {
|
||||
Parse(yyLex) int
|
||||
Lookahead() int
|
||||
}
|
||||
|
||||
Parse runs the parser; the top-level call yyParse(yylex) is equivalent
|
||||
to yyNewParser().Parse(yylex).
|
||||
|
||||
Lookahead can be called during grammar actions to read (but not consume)
|
||||
the value of the current lookahead token, as returned by yylex.Lex.
|
||||
If there is no current lookahead token (because the parser has not called Lex
|
||||
or has consumed the token returned by the most recent call to Lex),
|
||||
Lookahead returns -1. Calling Lookahead is equivalent to reading
|
||||
yychar from within in a grammar action.
|
||||
|
||||
Multiple grammars compiled into a single program should be placed in
|
||||
distinct packages. If that is impossible, the "-p prefix" flag to
|
||||
goyacc sets the prefix, by default yy, that begins the names of
|
||||
symbols, including types, the parser, and the lexer, generated and
|
||||
referenced by yacc's generated code. Setting it to distinct values
|
||||
allows multiple grammars to be placed in a single package.
|
||||
|
||||
*/
|
||||
package main
|
20
cmd/goyacc/testdata/expr/README
vendored
Normal file
20
cmd/goyacc/testdata/expr/README
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
This directory contains a simple program demonstrating how to use
|
||||
the Go version of yacc.
|
||||
|
||||
To build it:
|
||||
|
||||
$ go generate
|
||||
$ go build
|
||||
|
||||
or
|
||||
|
||||
$ go generate
|
||||
$ go run expr.go
|
||||
|
||||
The file main.go contains the "go generate" command to run yacc to
|
||||
create expr.go from expr.y. It also has the package doc comment,
|
||||
as godoc will not scan the .y file.
|
||||
|
||||
The actual implementation is in expr.y.
|
||||
|
||||
The program is not installed in the binary distributions of Go.
|
202
cmd/goyacc/testdata/expr/expr.y
vendored
Normal file
202
cmd/goyacc/testdata/expr/expr.y
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
// 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})
|
||||
}
|
||||
}
|
14
cmd/goyacc/testdata/expr/main.go
vendored
Normal file
14
cmd/goyacc/testdata/expr/main.go
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2014 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 file holds the go generate command to run yacc on the grammar in expr.y.
|
||||
// To build expr:
|
||||
// % go generate
|
||||
// % go build
|
||||
|
||||
//go:generate goyacc -o expr.go -p "expr" expr.y
|
||||
|
||||
// Expr is a simple expression evaluator that serves as a working example of
|
||||
// how to use Go's yacc implementation.
|
||||
package main
|
3641
cmd/goyacc/yacc.go
Normal file
3641
cmd/goyacc/yacc.go
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user