yacc: expr 例子完善, 包含生成的代码

This commit is contained in:
chai2010 2023-02-19 23:15:29 +08:00
parent 4b725e0a0c
commit c5035ebd93
5 changed files with 554 additions and 7 deletions

2
.gitignore vendored
View File

@ -16,7 +16,7 @@ wat2wasm.exe
*.out*
*.wasm
*.wasm.*
y.*
y.wa.*
/docs/snake/*

View File

@ -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*

View File

@ -1,7 +1,7 @@
// 版权 @2023 凹语言 作者。保留所有权利。
%{
package main
// 这是 凹语言 yacc 的例子, 用于对表达式进行解析, 为了简化词法部分暂时通过手工录入.
%}
%union {

551
_examples/expr/y.wa Normal file
View File

@ -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
}

View File

@ -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'