我正在尝试用 Java 创建一个可以识别这段代码的语法分析器(使用 CUP):
if ¿b? then
~ a = 2;
~ if ¿b && c? then
~ ~ a = 3;
else
~ a = 4;
“if”语句使用的产品如下:
Instr ::= ...
| IF CONOP Exp:e CONCL THEN CondInstrList:l
...
;
...
CondInstrList ::= CondInstrList CondInstr
| /*empty*/
;
...
CondInstr ::= CONTROLD Instr
| CONTROLD CondInstr
;
其中 Instr 代表指令/语句,CondInstrList 代表条件指令列表,CONTROLD 代表控制破折号 (~)。 (CONOP 和 CONCL 表示条件打开/关闭)
问题在于使用该语法,生成的 AST 如下:
if
|-condition b
|-condInstrListT
|---asig a = 2
|---if
|---condition b and c
|---condInstrListT
| |---asig a = 2
|---condInstrListF
|---asig a = 4
因此,“else”部分与内部“if”相关联。
我只是不知道如何编写符合我希望我的语言的方式的语法。
感谢任何帮助。
如果需要,我可以提供更多细节。
最佳答案
我不认为单靠语法就可以做到你想做的事。但是使用稍微不同的语法和词法分析器的一些帮助是可能的。
这里是要做的:与其将 ~ 标记视为单独的语法符号,不如让词法分析器将行首的 ~ 序列转换为 INDENT 和 OUTDENT 标记,它们在语法中的工作方式与 { 和在 Java 中工作。您跟踪从零开始的“当前缩进级别”。在每一行的开头,计算 ~ 字符。对于超过当前缩进级别的每个 ~,生成一个 INDENT 标记并增加当前缩进级别;对于每个小于当前缩进级别的 ~,生成一个 OUTDENT 标记并降低当前缩进级别。
因此您的示例文本为
if ¿b? then
~ a = 2;
~ if ¿b && c? then
~ ~ a = 3;
else
~ a = 4;
将被标记为:
// Indent level = 0 and no ~, so no INDENT here
[IF] [CONOP] [ID b] [CONCL] [THEN]
// Indent level = 0, one ~, so one INDENT
[INDENT]
// Indent level = 1
[ID a] [OP =] [CONST 2] [SEMICOLON]
// Indent level = 1, one ~, so no INDENT here
[IF] [CONOP] [ID b] [OP &&] [ID c] [CONCL] [THEN]
// Indent level = 1, two ~, so one INDENT
[INDENT]
// Indent level = 2
[ID a] [ASSIGN] [CONST 3] [SEMICOLON]
// Indent level = 2, lines starts with no ~, two OUTDENTs
[OUTDENT]
// Indent level = 1
[OUTDENT]
//Indent level = 0
[ELSE] // No ~ at start of this line, so no INDENT
// Indent level = 0; one ~, so one INDENT
[INDENT]
// Indent level = 1
[ID a] [ASSIGN] [CONST 4] [SEMICOLON]
// End-of-input. Indent level = 1, so 1 OUTDENT
[OUTDENT]
// Done; indent level = 0;
INDENT 和 OUTDENT 标记在您的语法中的作用类似于 Java 中的左右大括号,因此您的语法可能类似于:
Instr ::= ...
| IF CONOP Exp:e CONCL THEN INDENT CondInstrList:l OUTDENT
...
;
...
CondInstrList ::= CondInstrList Instr
| /*empty*/
;
...
Python 语言做同样的事情,但只是使用空格而不是 ~。可以下载Python源码here如果你有兴趣。查找文件 Grammar\Grammar
和 Parser\tokenizer.c
。
关于java - 如何为嵌套的 "if"指令定义使用多个破折号的语法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44014564/