Java 如何定义将多个破折号用于嵌套“的语法”;如果;说明书

Java 如何定义将多个破折号用于嵌套“的语法”;如果;说明书,java,syntax,grammar,cup,Java,Syntax,Grammar,Cup,我正在尝试用Java创建一个语法分析器(使用),可以识别这段代码: 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 Co

我正在尝试用Java创建一个语法分析器(使用),可以识别这段代码:

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”相关联

我只是不知道如何写出符合我所希望的语言风格的语法

感谢您的帮助


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

我认为你不可能仅仅通过语法就能做到你想做的事情。但是,如果语法稍有不同,并且在词法分析器的帮助下,这是可能的

下面是要做的事情:与其将~标记作为单独的语法符号来处理,不如让词法分析器将行开头的~序列转换为缩进和缩进标记,它们在语法中的工作方式与{和}在Java中的工作方式相同。跟踪从零开始的“当前缩进级别”。在每行的开头,计算~个字符。对于超过当前缩进级别的每个~,生成缩进标记并增加当前缩进级别;对于每一个小于当前缩进级别的标记,生成一个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;
缩进和向外缩进标记在语法中的作用类似于Java中的左大括号和右大括号,因此语法可能类似于:

Instr ::= ...
       | IF CONOP Exp:e CONCL THEN INDENT CondInstrList:l OUTDENT
       ...
       ;
...
CondInstrList ::= CondInstrList Instr
       | /*empty*/
       ;
...

Python语言也做了同样的事情,但只使用了空格而不是~。如果您感兴趣,可以下载Python源代码。查找文件
Grammar\Grammar
Parser\tokenizer.c

,这正是解决方案。现在我对JLex有一个问题。我将缩进级别存储在一个名为
indent
的属性中,每行末尾我都将实际缩进级别(属性
actual
)的计数器重置为0。这样,当实际缩进比第一级缩进多出一个破折号时,返回缩进符号。当我必须归还出口时,问题就出现了。我就是不知道怎么做,因为JLex只返回一个值。我可以找出需要减去多少“缩进级别”,但我无法返回所需的OUTDENT符号。我认为您需要能够重新读取输入,以便直接在词法分析器中生成正确的OUTDENT标记,我没有看到任何证据表明JLex可以做到这一点。您可能需要在解析器和词法分析器之间有一个中间层,该层可以从词法分析器接收关于每行缩进级别的信息,并计算出要返回到扫描程序的缩进或缩进标记的正确数量。最后一句应为“…要返回到解析器的标记”