goyacc初体验

google 的go语言里呆了goyacc工具,使用方法基本类似于贝尔实验室的yacc工具. 所以熟悉了解yacc工具的人应该比较容易掌握。不过网上几乎没有找到详细的step by step。 虽然yacc方面的资料比较多, 但是具体细节上goyacc还是有些不同的。所幸在源代码里有一个sample。具体位置是~/go/src/cmd/goyacc/units.y. 算是比较详细。于是照猫画虎,经过代码裁剪,我自己写了个简单的表达式计算器goexpr。
一个.y文件中, 由^%{ 和 ^%}包括的部分, 是嵌入代码。 %%中间的部分则是要解析的LALR(1)文法,其定义是非常直接的。
于yacc不同的是, goyacc没有配套的lex/flex程序, 需要手工写一个方法 Lex()来得到所有的token. 还要写一个方法Error作为出错时的回调函数。除此之外都是顺水顺风的比较简单的东西。
使用方法
goyacc goexpr.y && 6g y.go && 6l -o goexpr y.6
如果是x86架构,则把6换成8即可

代码如下

%{
package main
import (
"fmt"
"os"
"io/ioutil"
"flag"
"bufio"
)
var fi *bufio.Reader
var peekrune int
var data []byte
var linep int = 0
var finalval float = 0
%}

%union
{
vvar string;
numval float;
}

%token NUMBER
%token OP

%%
expr:
expr1
| expr '+' expr1
{
$$.numval = $1.numval + $3.numval
finalval = $$.numval
}
| expr '-' expr1
{
$$.numval = $1.numval - $3.numval
finalval = $$.numval
}

expr1:
NUMBER
| expr1 '*' NUMBER
{
$$.numval = $1.numval * $3.numval
finalval = $$.numval
}
| expr1 '/' NUMBER
{
$$.numval = $1.numval /
$3.numval
finalval = $$.numval
}

%%

func getrune() int {
if linep >= len(data) {
return 0
}
c := data[linep]

return int(c)
}

func next() {
linep++
}

func getnumber(c int) int {
var n int = 0
for ;c>='0' && c <= '9'; {
n += (c - '0')
next()
c = getrune()
}
yylval.numval = float(n)
return NUMBER

}

func readblank() {
var c int
for c = getrune(); c == ' '; {
next()
c = getrune()
}
}

func Lex() int {
var c int
readblank()
c = getrune()
if c >= '0' && c <= '9' {
return getnumber(c)
}
switch c {
case '+', '-', '*', '/':
yylval.vvar = string(c)
next()
return c
}
return c
}

func Error(s string, v ...) {
fmt.Printf("ERROR:%s\n", s)

}

func main() {
if flag.NArg() == 0 {
fmt.Printf("Usage goexpr <expr file>\n")
os.Exit(1)
}
file := flag.Arg(0)
f, err := os.Open(file, os.O_RDONLY, 0)
if err != nil {
fmt.Printf("Error opening %v: %v", file, err)
os.Exit(2)
}
data, err = ioutil.ReadAll(f)
if err != nil {
fmt.Printf("Error reading file %v, %v\n", file, err)
os.Exit(3)
}

Parse() // Parse the data
fmt.Printf("result = %g\n", finalval)
}



这段代码中, 如果 $3.numval 写成和上面一行, 这样
$$.numval = $1.numval / $3.numval
就会报错。 [quote]y.go:61: syntax error: unexpected $[/quote], 从源代码中看到,似乎"/" 被当成了单行注释的开始, 疑似bug, 待会儿汇报。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值