我正在公司项目上工作,我必须使用 Ocamlyacc 和 Ocamllex 为一种语言创建一个编译器。我想知道是否可以在我的 Ocamlyacc 解析器中定义一个规则,它可以告诉我我的语法规则没有匹配输入的语法。
我必须坚持我是 Ocamllex/Ocamlyacc 的初学者
非常感谢您的帮助。
如果语法中没有规则与输入匹配,则会Parsing.Parse_error
引发异常。通常,这就是您想要的。
还有一个名为的特殊令牌error
允许您重新同步解析器状态。您可以在规则中使用它,因为它是由词法分析器生成的真实标记,参见eof
标记。
另外,我建议使用menhir
而不是更古老的ocamlyacc
. 它更易于使用和调试,并且还带有一个很好的预定义语法库。
当您为一种语言编写编译器时,第一步是运行您的词法分析器并从词法的角度检查您的程序是否良好。
请参见下面的示例:
{
open Parser (* The type token is defined in parser.mli *)
exception Eof
}
rule token = parse
[' ' '\t'] { token lexbuf } (* skip blanks *)
| ['\n' ] { EOL }
| ['0'-'9']+ as lxm { INT(int_of_string lxm) }
| '+' { PLUS }
| '-' { MINUS }
| '*' { TIMES }
| '/' { DIV }
| '(' { LPAREN }
| ')' { RPAREN }
| eof { raise Eof }
它是识别一些算术表达式的词法分析器。
如果您的词法分析器接受输入,那么您将词位序列提供给解析器,解析器尝试查找是否可以使用指定的语法构建 AST。看 :
%token <int> INT
%token PLUS MINUS TIMES DIV
%token LPAREN RPAREN
%token EOL
%left PLUS MINUS /* lowest precedence */
%left TIMES DIV /* medium precedence */
%nonassoc UMINUS /* highest precedence */
%start main /* the entry point */
%type <int> main
%%
main:
expr EOL { $1 }
;
expr:
INT { $1 }
| LPAREN expr RPAREN { $2 }
| expr PLUS expr { $1 + $3 }
| expr MINUS expr { $1 - $3 }
| expr TIMES expr { $1 * $3 }
| expr DIV expr { $1 / $3 }
| MINUS expr %prec UMINUS { - $2 }
;
这是一个解析算术表达式的小程序。一个程序可以在这一步被拒绝,因为没有语法规则可以应用,以便在末尾有一个 AST。无法定义无法识别的规则,但您需要编写一个语法来定义程序如何被接受或拒绝。
let _ =
try
let lexbuf = Lexing.from_channel stdin in
while true do
let result = Parser.main Lexer.token lexbuf in
print_int result; print_newline(); flush stdout
done
with Lexer.Eof ->
exit 0
如果你编译词法分析器、解析器和最后一个程序,你有:
1 + 2
被接受,因为没有错误词法错误,并且可以构建与此表达式相对应的 AST。1 ++ 2
被拒绝:没有词法错误,但没有建立这样的 AST 的规则。您可以在此处找到更多文档:http: //caml.inria.fr/pub/docs/manual-ocaml-4.00/manual026.html