我已经编写了可以解析subroutine
的parser_sub.mly
和lexer_sub.mll
。subroutine
是由Sub
和End Sub
包围的语句块。
实际上,我想处理的原始文件包含子例程列表和一些无用的文本。下面是一个示例:
' a example file
Sub f1()
...
End Sub
haha
' hehe
Sub f2()
...
End Sub
所以我需要编写parser.mly
和lexer.mll
,它可以通过忽略所有注释来解析此文件(例如 haha
、' hehe
等)并调用 parser_sub.main
,并返回子例程的列表。
谁能告诉我如何让解析器忽略所有无用的句子(
Sub
和End Sub
之外的句子)?这是我尝试写
parser.mly
的一部分:%{ open Syntax %} %start main %type <Syntax.ev> main %% main: subroutine_declaration* { $1 }; subroutine_declaration: SUB name = subroutine_name LPAREN RPAREN EOS body = procedure_body? END SUB { { subroutine_name = name; procedure_body_EOS_opt = body; } }
procedure_body
的规则和解析很复杂,实际上是在parser_sub.mly
和lexer_sub.mll
中定义的,所以我怎么能让parser.mly
和lexer.mll
不重复定义它,而只是调用parser_sub.main
?
也许我们可以在子例程中设置一些标志:
sub_starts:
SUB { inside:=true };
sub_ends:
ENDSUB { inside:=false };
subroutine_declaration:
sub_starts name body sub_ends { ... }
当未设置此标志时,您只需跳过任何输入?
如果你想要跳过的东西可以有任何形式(不一定是你的语言的有效标记),你几乎必须通过破解你的词法分析器来解决这个问题,正如 Kakadu 所建议的那样。无论如何,这可能是最简单的事情。
如果填充物(要跳过的内容)由有效令牌组成,并且您想使用语法规则跳过,在我看来,主要问题是定义一个与 END 以外的任何标记匹配的非终端。保持最新状态会令人不快,但似乎是可能的。
最后,您会遇到一个问题,即结束标记是两个符号,END SUB。您必须处理看到 END 后跟 SUB 的情况。这甚至更棘手,因为 SUB 也是您的开始标记。同样,简化这一点的一种方法是破解您的词法分析器,以便它将 END SUB 视为单个令牌。(通常这比你想象的要棘手,比如如果你想允许 END 和 SUB 之间的注释。