forked from wa-lang/wa
yacc: expr 例子完善, 包含生成的代码
This commit is contained in:
parent
4b725e0a0c
commit
c5035ebd93
|
|
@ -16,7 +16,7 @@ wat2wasm.exe
|
|||
*.out*
|
||||
*.wasm
|
||||
*.wasm.*
|
||||
y.*
|
||||
y.wa.*
|
||||
|
||||
/docs/snake/*
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,5 @@ default:
|
|||
go run ../../main.go yacc -l -p=expr -c="copyright.txt" -o="y.wa" expr.y
|
||||
go run ../../main.go y.wa
|
||||
|
||||
dev:
|
||||
go run ../../main.go yacc -l -p=expr -c="copyright.txt" -o="y.wa.go" expr.y
|
||||
go run y.wa.go
|
||||
|
||||
clean:
|
||||
-rm y.* a.out*
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// 版权 @2023 凹语言 作者。保留所有权利。
|
||||
|
||||
%{
|
||||
package main
|
||||
// 这是 凹语言 yacc 的例子, 用于对表达式进行解析, 为了简化词法部分暂时通过手工录入.
|
||||
%}
|
||||
|
||||
%union {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,551 @@
|
|||
// 版权 @2019 凹语言 作者。保留所有权利。
|
||||
|
||||
// Code generated by 'wa yacc yacc -l -p=expr -c=copyright.txt -o=y.wa expr.y'. DO NOT EDIT.
|
||||
|
||||
// 这是 凹语言 yacc 的例子, 用于对表达式进行解析, 为了简化词法部分暂时通过手工录入.
|
||||
|
||||
import "strconv" => __yystrconv__
|
||||
|
||||
type exprSymType struct {
|
||||
yys :int
|
||||
num :int
|
||||
}
|
||||
|
||||
const NUM = 57346
|
||||
|
||||
var exprToknames = [...]string{
|
||||
"$end",
|
||||
"error",
|
||||
"$unk",
|
||||
"'+'",
|
||||
"'-'",
|
||||
"'*'",
|
||||
"'/'",
|
||||
"'('",
|
||||
"')'",
|
||||
"NUM",
|
||||
}
|
||||
|
||||
var exprStatenames = [...]string{}
|
||||
|
||||
const exprEofCode = 1
|
||||
const exprErrCode = 2
|
||||
const exprInitialStackSize = 16
|
||||
|
||||
// Lex 结束标志
|
||||
const eof = 0
|
||||
|
||||
type exprToken struct {
|
||||
Kind :int
|
||||
Value :int
|
||||
}
|
||||
|
||||
type exprLexer struct {
|
||||
tokens :[]exprToken
|
||||
pos :int
|
||||
}
|
||||
|
||||
func (p: *exprLexer) Lex(yylval: *exprSymType) => int {
|
||||
if p.pos >= len(p.tokens) {
|
||||
return eof
|
||||
}
|
||||
tok := p.tokens[p.pos]
|
||||
p.pos++
|
||||
|
||||
yylval.num = tok.Value
|
||||
return tok.Kind
|
||||
}
|
||||
|
||||
func (x: *exprLexer) Error(s: string) {
|
||||
println("ERROR:", s)
|
||||
}
|
||||
|
||||
func main() {
|
||||
print("1+2*(3+4)-10 = ")
|
||||
exprParse(&exprLexer{
|
||||
tokens: []exprToken{
|
||||
{Kind: NUM, Value: 1},
|
||||
{Kind: '+'},
|
||||
{Kind: NUM, Value: 2},
|
||||
{Kind: '*'},
|
||||
{Kind: '('},
|
||||
{Kind: NUM, Value: 3},
|
||||
{Kind: '+'},
|
||||
{Kind: NUM, Value: 4},
|
||||
{Kind: ')'},
|
||||
{Kind: '-'},
|
||||
{Kind: NUM, Value: 10},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
var exprExca = [...]int{
|
||||
-1, 1,
|
||||
1, -1,
|
||||
-2, 0,
|
||||
}
|
||||
|
||||
const exprPrivate = 57344
|
||||
|
||||
const exprLast = 23
|
||||
|
||||
var exprAct = [...]int{
|
||||
7, 4, 5, 2, 21, 9, 6, 8, 12, 13,
|
||||
9, 1, 8, 16, 3, 19, 20, 17, 18, 14,
|
||||
15, 10, 11,
|
||||
}
|
||||
|
||||
var exprPact = [...]int{
|
||||
-3, -1000, -1000, 17, -3, -3, 13, -1000, -1000, -3,
|
||||
2, 2, -1000, -1000, 2, 2, -5, 13, 13, -1000,
|
||||
-1000, -1000,
|
||||
}
|
||||
|
||||
var exprPgo = [...]int{
|
||||
0, 3, 14, 6, 0, 11,
|
||||
}
|
||||
|
||||
var exprR1 = [...]int{
|
||||
0, 5, 1, 1, 1, 2, 2, 2, 3, 3,
|
||||
3, 4, 4,
|
||||
}
|
||||
|
||||
var exprR2 = [...]int{
|
||||
0, 1, 1, 2, 2, 1, 3, 3, 1, 3,
|
||||
3, 1, 3,
|
||||
}
|
||||
|
||||
var exprChk = [...]int{
|
||||
-1000, -5, -1, -2, 4, 5, -3, -4, 10, 8,
|
||||
4, 5, -1, -1, 6, 7, -1, -3, -3, -4,
|
||||
-4, 9,
|
||||
}
|
||||
|
||||
var exprDef = [...]int{
|
||||
0, -2, 1, 2, 0, 0, 5, 8, 11, 0,
|
||||
0, 0, 3, 4, 0, 0, 0, 6, 7, 9,
|
||||
10, 12,
|
||||
}
|
||||
|
||||
var exprTok1 = [...]int{
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
8, 9, 6, 4, 3, 5, 3, 7,
|
||||
}
|
||||
|
||||
var exprTok2 = [...]int{
|
||||
2, 3, 10,
|
||||
}
|
||||
|
||||
var exprTok3 = [...]int{
|
||||
0,
|
||||
}
|
||||
|
||||
type exprErrorMessageInfo struct {
|
||||
state :int
|
||||
token :int
|
||||
msg :string
|
||||
}
|
||||
|
||||
var exprErrorMessages = [...]exprErrorMessageInfo{}
|
||||
|
||||
/* parser for yacc output */
|
||||
|
||||
var (
|
||||
exprDebug = 0
|
||||
exprErrorVerbose = false
|
||||
)
|
||||
|
||||
type exprParser struct {
|
||||
lval :exprSymType
|
||||
stack :[exprInitialStackSize]exprSymType
|
||||
char :int
|
||||
}
|
||||
|
||||
func (p: *exprParser) Lookahead() => int {
|
||||
return p.char
|
||||
}
|
||||
|
||||
func exprNewParser() => *exprParser {
|
||||
return &exprParser{}
|
||||
}
|
||||
|
||||
const exprFlag = -1000
|
||||
|
||||
func exprTokname(c: int) => string {
|
||||
if c >= 1 && c-1 < len(exprToknames) {
|
||||
if exprToknames[c-1] != "" {
|
||||
return exprToknames[c-1]
|
||||
}
|
||||
}
|
||||
return "tok-" + __yystrconv__.Itoa(c)
|
||||
}
|
||||
|
||||
func exprStatname(s: int) => string {
|
||||
if s >= 0 && s < len(exprStatenames) {
|
||||
if exprStatenames[s] != "" {
|
||||
return exprStatenames[s]
|
||||
}
|
||||
}
|
||||
return "state-" + __yystrconv__.Itoa(s)
|
||||
}
|
||||
|
||||
func exprErrorMessage(state, lookAhead: int) => string {
|
||||
const TOKSTART = 4
|
||||
|
||||
if !exprErrorVerbose {
|
||||
return "syntax error"
|
||||
}
|
||||
|
||||
for _, e := range exprErrorMessages {
|
||||
if e.state == state && e.token == lookAhead {
|
||||
return "syntax error: " + e.msg
|
||||
}
|
||||
}
|
||||
|
||||
res := "syntax error: unexpected " + exprTokname(lookAhead)
|
||||
|
||||
// To match Bison, suggest at most four expected tokens.
|
||||
expected := make([]int, 0, 4)
|
||||
|
||||
// Look for shiftable tokens.
|
||||
base := exprPact[state]
|
||||
for tok := TOKSTART; tok-1 < len(exprToknames); tok++ {
|
||||
if n := base + tok; n >= 0 && n < exprLast && exprChk[exprAct[n]] == tok {
|
||||
if len(expected) == cap(expected) {
|
||||
return res
|
||||
}
|
||||
expected = append(expected, tok)
|
||||
}
|
||||
}
|
||||
|
||||
if exprDef[state] == -2 {
|
||||
i := 0
|
||||
for exprExca[i] != -1 || exprExca[i+1] != state {
|
||||
i += 2
|
||||
}
|
||||
|
||||
// Look for tokens that we accept or reduce.
|
||||
for i += 2; exprExca[i] >= 0; i += 2 {
|
||||
tok := exprExca[i]
|
||||
if tok < TOKSTART || exprExca[i+1] == 0 {
|
||||
continue
|
||||
}
|
||||
if len(expected) == cap(expected) {
|
||||
return res
|
||||
}
|
||||
expected = append(expected, tok)
|
||||
}
|
||||
|
||||
// If the default action is to accept or reduce, give up.
|
||||
if exprExca[i+1] != 0 {
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
for i, tok := range expected {
|
||||
if i == 0 {
|
||||
res += ", expecting "
|
||||
} else {
|
||||
res += " or "
|
||||
}
|
||||
res += exprTokname(tok)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func exprlex1(lex: *exprLexer, lval: *exprSymType) => (char, token: int) {
|
||||
token = 0
|
||||
char = lex.Lex(lval)
|
||||
|
||||
out:
|
||||
for {
|
||||
if char <= 0 {
|
||||
token = exprTok1[0]
|
||||
break out
|
||||
}
|
||||
if char < len(exprTok1) {
|
||||
token = exprTok1[char]
|
||||
break out
|
||||
}
|
||||
if char >= exprPrivate {
|
||||
if char < exprPrivate+len(exprTok2) {
|
||||
token = exprTok2[char-exprPrivate]
|
||||
break out
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(exprTok3); i += 2 {
|
||||
token = exprTok3[i+0]
|
||||
if token == char {
|
||||
token = exprTok3[i+1]
|
||||
break out
|
||||
}
|
||||
}
|
||||
break out
|
||||
}
|
||||
|
||||
if token == 0 {
|
||||
token = exprTok2[1] /* unknown char */
|
||||
}
|
||||
if exprDebug >= 3 {
|
||||
println("lex " + exprTokname(token) + "(" + __yystrconv__.Itoa(char) + ")")
|
||||
}
|
||||
return char, token
|
||||
}
|
||||
|
||||
func exprParse(exprlex: *exprLexer) => int {
|
||||
return exprNewParser().Parse(exprlex)
|
||||
}
|
||||
|
||||
func (exprrcvr: *exprParser) Parse(exprlex: *exprLexer) => int {
|
||||
var exprn: int
|
||||
var exprVAL: exprSymType
|
||||
var exprDollar: []exprSymType
|
||||
_ = exprDollar // silence set and not used
|
||||
exprS := exprrcvr.stack[:]
|
||||
|
||||
Nerrs := 0 /* number of errors */
|
||||
Errflag := 0 /* error recovery flag */
|
||||
exprstate := 0
|
||||
exprrcvr.char = -1
|
||||
exprtoken := -1 // exprrcvr.char translated into internal numbering
|
||||
exprp := -1
|
||||
|
||||
const __goto_exprstack = -1
|
||||
const __goto_exprnewstate = -2
|
||||
const __goto_exprdefault = -3
|
||||
var __goto_x = __goto_exprstack
|
||||
|
||||
Loop:
|
||||
for {
|
||||
switch __goto_x {
|
||||
case __goto_exprstack:
|
||||
/* put a state and value onto the stack */
|
||||
if exprDebug >= 4 {
|
||||
println("char " + exprTokname(exprtoken) + " in " + exprStatname(exprstate))
|
||||
}
|
||||
|
||||
exprp++
|
||||
if exprp >= len(exprS) {
|
||||
nyys := make([]exprSymType, len(exprS)*2)
|
||||
for i := 0; i < len(exprS); i++ {
|
||||
nyys[i] = exprS[i]
|
||||
}
|
||||
exprS = nyys
|
||||
}
|
||||
exprS[exprp] = exprVAL
|
||||
exprS[exprp].yys = exprstate
|
||||
|
||||
__goto_x = __goto_exprnewstate
|
||||
continue Loop
|
||||
|
||||
case __goto_exprnewstate:
|
||||
exprn = exprPact[exprstate]
|
||||
if exprn <= exprFlag {
|
||||
/* simple state */
|
||||
__goto_x = __goto_exprdefault
|
||||
continue Loop
|
||||
}
|
||||
if exprrcvr.char < 0 {
|
||||
exprrcvr.char, exprtoken = exprlex1(exprlex, &exprrcvr.lval)
|
||||
}
|
||||
exprn += exprtoken
|
||||
if exprn < 0 || exprn >= exprLast {
|
||||
__goto_x = __goto_exprdefault
|
||||
continue Loop
|
||||
}
|
||||
exprn = exprAct[exprn]
|
||||
if exprChk[exprn] == exprtoken { /* valid shift */
|
||||
exprrcvr.char = -1
|
||||
exprtoken = -1
|
||||
exprVAL = exprrcvr.lval
|
||||
exprstate = exprn
|
||||
if Errflag > 0 {
|
||||
Errflag--
|
||||
}
|
||||
__goto_x = __goto_exprstack
|
||||
continue Loop
|
||||
}
|
||||
|
||||
__goto_x = __goto_exprdefault
|
||||
continue Loop
|
||||
|
||||
case __goto_exprdefault:
|
||||
/* default state action */
|
||||
exprn = exprDef[exprstate]
|
||||
if exprn == -2 {
|
||||
if exprrcvr.char < 0 {
|
||||
exprrcvr.char, exprtoken = exprlex1(exprlex, &exprrcvr.lval)
|
||||
}
|
||||
|
||||
/* look through exception table */
|
||||
xi := 0
|
||||
for {
|
||||
if exprExca[xi+0] == -1 && exprExca[xi+1] == exprstate {
|
||||
break
|
||||
}
|
||||
xi += 2
|
||||
}
|
||||
for xi += 2; ; xi += 2 {
|
||||
exprn = exprExca[xi+0]
|
||||
if exprn < 0 || exprn == exprtoken {
|
||||
break
|
||||
}
|
||||
}
|
||||
exprn = exprExca[xi+1]
|
||||
if exprn < 0 {
|
||||
// Make sure we report no lookahead when not parsing.
|
||||
exprstate = -1
|
||||
exprrcvr.char = -1
|
||||
exprtoken = -1
|
||||
|
||||
return 0
|
||||
}
|
||||
}
|
||||
if exprn == 0 {
|
||||
/* error ... attempt to resume parsing */
|
||||
switch Errflag {
|
||||
case 0, 1, 2: /* incompletely recovered error ... try again */
|
||||
if Errflag == 0 {
|
||||
exprlex.Error(exprErrorMessage(exprstate, exprtoken))
|
||||
Nerrs++
|
||||
if exprDebug >= 1 {
|
||||
println(exprStatname(exprstate) + " saw " + exprTokname(exprtoken))
|
||||
}
|
||||
}
|
||||
Errflag = 3
|
||||
|
||||
/* find a state where "error" is a legal shift action */
|
||||
for exprp >= 0 {
|
||||
exprn = exprPact[exprS[exprp].yys] + exprErrCode
|
||||
if exprn >= 0 && exprn < exprLast {
|
||||
exprstate = exprAct[exprn] /* simulate a shift of "error" */
|
||||
if exprChk[exprstate] == exprErrCode {
|
||||
__goto_x = __goto_exprstack
|
||||
continue Loop
|
||||
}
|
||||
}
|
||||
|
||||
/* the current p has no shift on "error", pop stack */
|
||||
if exprDebug >= 2 {
|
||||
println("error recovery pops state " + __yystrconv__.Itoa(exprS[exprp].yys))
|
||||
}
|
||||
exprp--
|
||||
}
|
||||
|
||||
// Make sure we report no lookahead when not parsing.
|
||||
exprstate = -1
|
||||
exprrcvr.char = -1
|
||||
exprtoken = -1
|
||||
|
||||
/* there is no state on the stack with an error shift ... abort */
|
||||
return 1
|
||||
|
||||
case 3: /* no shift yet; clobber input char */
|
||||
if exprDebug >= 2 {
|
||||
println("error recovery discards " + exprTokname(exprtoken))
|
||||
}
|
||||
if exprtoken == exprEofCode {
|
||||
// Make sure we report no lookahead when not parsing.
|
||||
exprstate = -1
|
||||
exprrcvr.char = -1
|
||||
exprtoken = -1
|
||||
|
||||
return 1
|
||||
}
|
||||
exprrcvr.char = -1
|
||||
exprtoken = -1
|
||||
|
||||
__goto_x = __goto_exprnewstate /* try again in the same state */
|
||||
continue Loop
|
||||
}
|
||||
}
|
||||
|
||||
/* reduction by production exprn */
|
||||
if exprDebug >= 2 {
|
||||
println("reduce " + __yystrconv__.Itoa(exprn) + " in:")
|
||||
println("\t" + exprStatname(exprstate))
|
||||
}
|
||||
|
||||
exprnt := exprn
|
||||
exprpt := exprp
|
||||
_ = exprpt // guard against "declared and not used"
|
||||
|
||||
exprp -= exprR2[exprn]
|
||||
// exprp is now the index of $0. Perform the default action. Iff the
|
||||
// reduced production is ε, $1 is possibly out of range.
|
||||
if exprp+1 >= len(exprS) {
|
||||
nyys := make([]exprSymType, len(exprS)*2)
|
||||
for i := 0; i < len(exprS); i++ {
|
||||
nyys[i] = exprS[i]
|
||||
}
|
||||
exprS = nyys
|
||||
}
|
||||
exprVAL = exprS[exprp+1]
|
||||
|
||||
/* consult goto table to find next state */
|
||||
exprn = exprR1[exprn]
|
||||
exprg := exprPgo[exprn]
|
||||
exprj := exprg + exprS[exprp].yys + 1
|
||||
|
||||
if exprj >= exprLast {
|
||||
exprstate = exprAct[exprg]
|
||||
} else {
|
||||
exprstate = exprAct[exprj]
|
||||
if exprChk[exprstate] != -exprn {
|
||||
exprstate = exprAct[exprg]
|
||||
}
|
||||
}
|
||||
// dummy call; replaced with literal code
|
||||
switch exprnt {
|
||||
|
||||
case 1:
|
||||
exprDollar = exprS[exprpt-1 : exprpt+1]
|
||||
{
|
||||
println(exprDollar[1].num)
|
||||
}
|
||||
case 3:
|
||||
exprDollar = exprS[exprpt-2 : exprpt+1]
|
||||
{
|
||||
exprVAL.num = exprDollar[2].num
|
||||
}
|
||||
case 4:
|
||||
exprDollar = exprS[exprpt-2 : exprpt+1]
|
||||
{
|
||||
exprVAL.num = -exprDollar[2].num
|
||||
}
|
||||
case 6:
|
||||
exprDollar = exprS[exprpt-3 : exprpt+1]
|
||||
{
|
||||
exprVAL.num = exprDollar[1].num + exprDollar[3].num
|
||||
}
|
||||
case 7:
|
||||
exprDollar = exprS[exprpt-3 : exprpt+1]
|
||||
{
|
||||
exprVAL.num = exprDollar[1].num - exprDollar[3].num
|
||||
}
|
||||
case 9:
|
||||
exprDollar = exprS[exprpt-3 : exprpt+1]
|
||||
{
|
||||
exprVAL.num = exprDollar[1].num * exprDollar[3].num
|
||||
}
|
||||
case 10:
|
||||
exprDollar = exprS[exprpt-3 : exprpt+1]
|
||||
{
|
||||
exprVAL.num = exprDollar[1].num / exprDollar[3].num
|
||||
}
|
||||
case 12:
|
||||
exprDollar = exprS[exprpt-3 : exprpt+1]
|
||||
{
|
||||
exprVAL.num = exprDollar[2].num
|
||||
}
|
||||
}
|
||||
|
||||
__goto_x = __goto_exprstack /* stack new state and value */
|
||||
continue Loop
|
||||
|
||||
} // switch
|
||||
} // for
|
||||
}
|
||||
|
|
@ -408,7 +408,7 @@ func setup() {
|
|||
fmt.Fprintf(ftable, "%s\n\n", strings.TrimSpace(copyright))
|
||||
}
|
||||
|
||||
fmt.Fprintf(ftable, "// Code generated by 'wa yacc %s'. DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
|
||||
fmt.Fprintf(ftable, "// Code generated by 'wa yacc %s'. DO NOT EDIT.\n\n", strings.Join(os.Args[1:], " "))
|
||||
|
||||
defin(0, "$end")
|
||||
extval = PRIVATE // tokens start in unicode 'private use'
|
||||
|
|
|
|||
Loading…
Reference in New Issue