我正在尝试用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代表Control Dash(〜)。 (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”相关联。
我只是不知道如何编写一种尊重我想要语言的语法。
感谢任何帮助。
如果需要,我可以提供更多细节。
答案 0 :(得分:1)
我不认为你可以通过语法单独完成你的想法。但是可以使用略有不同的语法和一些词法分析器的帮助。
这里要做什么:不是将〜标记视为单独的语法符号,而是将词法分析器在行开头处将〜的序列转换为将在语法中起作用的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
。