如何为嵌套的“if”指令定义使用多个破折号的语法?

时间:2017-05-17 02:35:14

标签: java syntax grammar cup

我正在尝试用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”相关联。

我只是不知道如何编写一种尊重我想要语言的语法。

感谢任何帮助。

如果需要,我可以提供更多细节。

1 个答案:

答案 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\GrammarParser\tokenizer.c