From c5035ebd93db2e209abea321ec4f8a0968ede1fb Mon Sep 17 00:00:00 2001 From: chai2010 Date: Sun, 19 Feb 2023 23:15:29 +0800 Subject: [PATCH] =?UTF-8?q?yacc:=20expr=20=E4=BE=8B=E5=AD=90=E5=AE=8C?= =?UTF-8?q?=E5=96=84,=20=E5=8C=85=E5=90=AB=E7=94=9F=E6=88=90=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- _examples/expr/Makefile | 4 - _examples/expr/expr.y | 2 +- _examples/expr/y.wa | 551 ++++++++++++++++++++++++++++++++++++++ internal/app/yacc/yacc.go | 2 +- 5 files changed, 554 insertions(+), 7 deletions(-) create mode 100644 _examples/expr/y.wa diff --git a/.gitignore b/.gitignore index 73675e1..62ad190 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ wat2wasm.exe *.out* *.wasm *.wasm.* -y.* +y.wa.* /docs/snake/* diff --git a/_examples/expr/Makefile b/_examples/expr/Makefile index 5404c7f..b9dfce6 100644 --- a/_examples/expr/Makefile +++ b/_examples/expr/Makefile @@ -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* diff --git a/_examples/expr/expr.y b/_examples/expr/expr.y index 0cdb39c..fdcc094 100644 --- a/_examples/expr/expr.y +++ b/_examples/expr/expr.y @@ -1,7 +1,7 @@ // 版权 @2023 凹语言 作者。保留所有权利。 %{ -package main +// 这是 凹语言 yacc 的例子, 用于对表达式进行解析, 为了简化词法部分暂时通过手工录入. %} %union { diff --git a/_examples/expr/y.wa b/_examples/expr/y.wa new file mode 100644 index 0000000..af7c16e --- /dev/null +++ b/_examples/expr/y.wa @@ -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 +} diff --git a/internal/app/yacc/yacc.go b/internal/app/yacc/yacc.go index bf4306c..db59e49 100644 --- a/internal/app/yacc/yacc.go +++ b/internal/app/yacc/yacc.go @@ -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'