解析器停止解析

时间:2011-05-06 21:27:18

标签: ocaml ocamlyacc

我完全没有想法。我今天每一分钟都花在这上面,但我完全没有想法。

这是我的Ocamlyacc语法:

input: /* empty */ { }
    | input stmt { }

stmt:
    extern { print_endline "Got an extern import" }
    | func  { print_endline "Got function definition" }
    | call  { print_endline "Got function call" }

extern:
    EXTERN proto { Extern $2 }  

func:
    DEF proto expr { Function ($2, $3) }

proto:
    IDENTIFIER LPAREN id_list RPAREN { print_endline "Got prototype definition"; Prototype ($1, $3) }

id_list:
    /* empty */ { [] }
    | IDENTIFIER { [$1] }
    | id_list COMMA IDENTIFIER { $3 :: $1 }

expr_list:
    /* empty */ { [] }
    | expr { [$1] }
    | expr_list COMMA expr { $3 :: $1 }

expr:
    call { $1 }
    | expr OP expr { Binary ($2, $1, $3) }
    | IDENTIFIER { Variable $1 }
    | NUMBER { Number $1 }
    | LPAREN expr RPAREN { $2 }

call:
    IDENTIFIER LPAREN expr_list RPAREN { Call ($1, $3) }

当我开始解析def foo(a,b) a+b时,根据调试消息,它应该告诉我它有一个函数和一个原型声明。但相反,我只收到解析proto规则的消息。

进一步的调试消息显示解析器到达表达式a的{​​{1}}然后停止。没有错误消息,没有别的。它就像完全解析整个文本框而不符合a+b中的任何规则一样停止。

没有移位/减少错误或类似错误。 AST类型也不是问题。我不知道了,也许别人可以提供帮助。当然这是明显的,但我看不到它。

编辑:受欢迎需求的Lexer:

stmt

1 个答案:

答案 0 :(得分:4)

第一点:我因为没有提供可编译的源代码而讨厌你。我不得不重新发明AST类型,%token声明等来测试你的代码。

问题是

之间的微妙相互作用
| eof { raise End_of_file }

lexing规则和你的语法。

如果您的语法从不自然地遇到文件的末尾,那么在词法分析器中提高Enf_of_file EOF是个好主意。例如,自然\n - 被终止或;;终止的语法将在此时停止解析,并且永远不会到达EOF令牌。

但你的语法不是其中之一。当解析器到达DEF proto expr .时,它会要求下一个令牌,以查看它是否是偶然的OP,因此它会调用找到EOF的词法分析器,并且打击。

这是我的修复:

在lex.mll中:

    | eof { EOF }

在parse.mly中:     %令牌EOF

%start stmt_eof
%type <Types.stmt> stmt_eof

[...]

stmt_eof: stmt EOF { $1 }

最后,您应该认真考虑Menhir作为ocamlyacc的替代品。它做的所有事情ocamlyacc都做得更好,只有更清晰的语法文件(例如,你不必每次都重新发明foo_list非终结符号),更好的错误信息,调试功能......