如何在 Ocamlyacc 中定义无法识别的规则
How to define unrecognized rules in Ocamlyacc
我在公司项目上工作,我必须使用 Ocamlyacc 和 Ocamllex 为一种语言创建一个编译器。我想知道是否可以在我的 Ocamlyacc 解析器中定义一个规则,它可以告诉我我的语法规则没有匹配输入的语法。
我必须坚持说我是 Ocamllex/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 { }
;
expr:
INT { }
| LPAREN expr RPAREN { }
| expr PLUS expr { + }
| expr MINUS expr { - }
| expr TIMES expr { * }
| expr DIV expr { / }
| MINUS expr %prec UMINUS { - }
;
这是一个解析算术表达式的小程序。一个程序可以在这一步被拒绝,因为没有语法规则可以应用以便在最后有一个 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
被接受是因为没有error lexical errors,可以构建对应这个表达式的AST。
1 ++ 2
被拒绝:没有词法错误,但没有构建这样的 AST 的规则。
您可以在此处找到更多文档:http://caml.inria.fr/pub/docs/manual-ocaml-4.00/manual026.html
如果您的语法中没有规则与输入相匹配,则会引发 Parsing.Parse_error
异常。通常,这就是您想要的。
还有一个名为 error
的特殊标记,可让您重新同步解析器状态。您可以在您的规则中使用它,因为它是由词法分析器生成的真实标记,参见 eof
标记。
此外,我建议使用 menhir
而不是更古老的 ocamlyacc
。它更易于使用和调试,并且还附带了一个很好的预定义语法库。
我在公司项目上工作,我必须使用 Ocamlyacc 和 Ocamllex 为一种语言创建一个编译器。我想知道是否可以在我的 Ocamlyacc 解析器中定义一个规则,它可以告诉我我的语法规则没有匹配输入的语法。
我必须坚持说我是 Ocamllex/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 { }
;
expr:
INT { }
| LPAREN expr RPAREN { }
| expr PLUS expr { + }
| expr MINUS expr { - }
| expr TIMES expr { * }
| expr DIV expr { / }
| MINUS expr %prec UMINUS { - }
;
这是一个解析算术表达式的小程序。一个程序可以在这一步被拒绝,因为没有语法规则可以应用以便在最后有一个 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
被接受是因为没有error lexical errors,可以构建对应这个表达式的AST。1 ++ 2
被拒绝:没有词法错误,但没有构建这样的 AST 的规则。
您可以在此处找到更多文档:http://caml.inria.fr/pub/docs/manual-ocaml-4.00/manual026.html
如果您的语法中没有规则与输入相匹配,则会引发 Parsing.Parse_error
异常。通常,这就是您想要的。
还有一个名为 error
的特殊标记,可让您重新同步解析器状态。您可以在您的规则中使用它,因为它是由词法分析器生成的真实标记,参见 eof
标记。
此外,我建议使用 menhir
而不是更古老的 ocamlyacc
。它更易于使用和调试,并且还附带了一个很好的预定义语法库。