如何在 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. 1 + 2被接受是因为没有error lexical errors,可以构建对应这个表达式的AST。
  2. 1 ++ 2 被拒绝:没有词法错误,但没有构建这样的 AST 的规则。

您可以在此处找到更多文档:http://caml.inria.fr/pub/docs/manual-ocaml-4.00/manual026.html

如果您的语法中没有规则与输入相匹配,则会引发 Parsing.Parse_error 异常。通常,这就是您想要的。

还有一个名为 error 的特殊标记,可让您重新同步解析器状态。您可以在您的规则中使用它,因为它是由词法分析器生成的真实标记,参见 eof 标记。

此外,我建议使用 menhir 而不是更古老的 ocamlyacc。它更易于使用和调试,并且还附带了一个很好的预定义语法库。