我正在读Terence Parr的最终ANTLR参考文献,他说:
语义谓词是一种强大的功能 识别上下文敏感的方法 允许的语言结构 要运行的运行时信息 识别
但书中的例子非常简单。我需要知道的是:ANTLR可以解析context-sensitive规则,如:
xAy - > XBY
如果ANTLR无法解析这些规则,是否还有另一种工具可以处理上下文敏感的语法?
答案 0 :(得分:9)
ANTLR只解析LL(*)的语法。它无法使用语法解析完整的上下文相关语言,例如您提供的示例。我认为Parr的意思是ANTLR可以解析某些需要某些(左)上下文约束的语言。
特别是,可以在“减少动作”上使用语义谓词(我们为GLR解析器执行此操作) 由我们的DMS Software Reengineering Toolkit使用,但我认为ANTLR的想法类似于检查解析器到目前为止收集的任何数据,或者作为其他语义动作的临时副作用,或者在部分构建的解析树中。
对于基于DMS的DMS-based Fortran front end,有一个上下文相关检查,以确保DO循环正确排列。考虑:
DO 20, I= ...
DO 10, J = ...
...
20 CONTINUE
10 CONTINUE
从解析器的角度来看,词汇流看起来像这样:
DO <number> , <variable> = ...
DO <number> , <variable> = ...
...
<number> CONTINUE
<number> CONTINUE
然后解析器如何知道哪个DO语句与哪个CONTINUE语句一起使用? (说每个DO匹配其最接近的CONTINUE将不起作用,因为FORTRAN可以 与多个DO头共享一个CONTINUE语句。
我们在减少以下规则时使用语义谓词“CheckMatchingNumbers”:
block = 'DO' <number> rest_of_do_head newline
block_of_statements
<number> 'CONTINUE' newline ; CheckMatchingNumbers
检查DO关键字后面的数字,以及CONTINUE关键字后面的数字是否匹配。如果语义谓词表明它们匹配,则此规则的减少成功,并且我们已将DO头与正确的CONTINUE对齐。如果谓词失败,则不提出减少(并且从解析本地上下文的候选者中删除此规则);其他一些规则必须解析文本。
使用共享continue来处理FORTRAN嵌套的实际规则和语义谓词比这更复杂,但我认为这是重点。
您想要的是完整的上下文相关解析引擎。我知道人们已经构建了它们,但我不知道任何完整的实现,并且不要指望它们很快。
我确实关注了Quinn Taylor Jackson's MetaS grammar system一段时间;这听起来像是接近实际的尝试。
答案 1 :(得分:0)
在Prolog中编写上下文敏感的解析器相对容易。该程序解析字符串[a,is,less,than,b,and,b,is,less,than,c]
,将其转换为[a,<,b,<,c]
:
:- initialization(main).
:- set_prolog_flag('double_quotes','chars').
main :-
rewrite_system([a,is,less,than,b,and,b,is,less,than,c],X),writeln('\nFinal output:'),writeln(X).
rewrite_rule([[A,<,B],and,[B,<,C]],[A,<,B,<,C]).
rewrite_rule([A,is,less,than,B],[A,<,B]).
rewrite_rule([[A,<,B],and,C,than,D],[[A,<,B],and,A,is,C,than,D]).
rewrite_rule([A,<,B],[[A,<,B]]).
rewritten(A) :- atom(A);bool(A).
bool(A) :- atom(A).
bool([A,<,B,<,C]) :- atom(A),atom(B),atom(C).
bool([A,and,B]) :- bool(A),bool(B).
% this predicate is from https://stackoverflow.com/a/8312742/975097
replace(ToReplace, ToInsert, List, Result) :-
once(append([Left, ToReplace, Right], List)),
append([Left, ToInsert, Right], Result).
rewrite_system(Input,Output) :-
rewritten(Input),Input=Output;
rewrite_rule(A,B),
replace(A,B,Input,Input1),
writeln(Input1),
rewrite_system(Input1,Output).
使用相同的算法,我还编写了一个adaptive parser,可以从其输入中“学习”新的重写规则。