2017-05-17 47 views
2

我試圖在Java中創建一個語法分析器(使用CUP),可以承認這段代碼:如何爲嵌套的「if」指令定義使用多個破折號的語法?

Instr ::= ... 
     | IF CONOP Exp:e CONCL THEN CondInstrList:l 
     ... 
     ; 
... 
CondInstrList ::= CondInstrList CondInstr 
     | /*empty*/ 
     ; 
... 
CondInstr ::= CONTROLD Instr 
     | CONTROLD CondInstr 
     ; 
:由「if」語句是這些遵循使用

if ¿b? then 
~ a = 2; 
~ if ¿b && c? then 
~ ~ a = 3; 
else 
~ a = 4; 

我的作品

其中Instr代表指令/語句,CondInstrList代表條件指令列表,CONTROLD代表控制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」部分與內相關的「如果」。

我只是不知道如何寫一個尊重我想我的語言的方式的語法。

任何幫助表示讚賞。

如果需要,我可以提供更多的細節。

回答

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; 

縮進和減少縮進標記在你的語法像Java中左,右括號辦將採取行動,所以你的語法可能看起來像這樣:

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

語言Python做同樣的事情,但無線網絡只是空白而不是〜。如果你有興趣,你可以下載Python源碼here。查找文件Grammar\GrammarParser\tokenizer.c

+0

這正是解決方案。現在我遇到了JLex的問題。我將縮進級別存儲在名爲'indent'的屬性中,並且第I行的每一端將實際縮進級別(屬性「actual」)的計數器重置爲0.這樣,當比實際縮進級別多一個短劃線我返回一個INDENT符號。當我必須返回OUTDENT時,問題就會浮現出來。我只是無法弄清楚如何做到這一點,因爲JLex只返回一個值。我可以找出需要減少多少「縮進級別」,但我無法根據需要返回儘可能多的OUTDENT符號。 –

+0

我認爲你需要重新閱讀輸入才能直接在詞法分析器中生成正確的OUTDENT標記,而且我沒有看到JLex可以做到的任何證據。您可能需要在解析器和詞法分析器之間有一箇中間層,它可以從詞法分析器接收有關每行縮進級別的信息,並找出正確數量的INDENT或OUTDENT標記以返回到掃描器。 –

+0

最後一句應該是「... tokens返回到**解析器**」。 –