我正在写一个解释器,使用ocamlyacc和ocamllex来编译我的解析器和lexer。
我的问题是,我有一个文件调用测试,包含2个在lexer中定义的命令:
print a
print b
但是,解释器仅执行行print a
!我知道问题主要在解析器中,需要递归。我将其定为这样(下面的代码),但仍然不起作用。
%{
open Path
%}
%token <int> INT
%token <string> STRING
%token EOL
%token EOF
%token GET_LINE
%token PRINT
%start main
%type <Path.term> main
%%
main:
| expr EOL {$1}
| expr EOF {$1}
;
str:
| STRING { $1 }
;
intger:
| INT {$1 }
;
expr:
| PRINT str { Print $2 }
| PRINT str expr { Print $2 }
| GET_LINE INT str { Print_line_in_file ($2, $3) }
| GET_LINE INT str expr { Print_line_in_file ($2, $3) }
;
编辑
这是我的词法,我试图尽可能简化它以发现错误。
(* File lexer.mll *)
{
open Parser
}
rule main = parse
| [' ''t''n'] { main lexbuf }
| "print_line_in_file" { GET_LINE }
| "print" { PRINT}
| ['1' - '9']+ as lxm { INT(int_of_string lxm) }
| ['a'-'z''A'-'Z'] ['a'-'z''A'-'Z''0'-'9']* as lxm { STRING lxm }
| eof {EOF}
main.ml
open Path
let _ =
try
let filename = Sys.argv.(1)
in
let lexbuf = Lexing.from_channel (open_in filename)
in
let result = Parser.main Lexer.main lexbuf
in
command result;
flush stdout
with Parsing.Parse_error -> print_string "Error! Check syntax";
flush stdout
要扩展Gasche的答案,您需要更改解析器的定义:
%type <Path.term list> main
%%
main:
| expr EOL main {$1::$3}
| expr EOF {[$1]}
| EOF {[]} /* if you want to allow a redundant EOL at the end */
;
使用您的原始定义,单行被认为是main
的完整解析,这就是为什么您的解析器在此之后停止的原因。
每次打电话给解析器时,它将仅解析一个表达式(这是您的起始规则的类型);它将停在线路末端(考虑到您在语法中使用EOL
的方式)。如果要解析几个表达式,则需要在循环中几次调用它。