2016-12-28 129 views
3

我解析的語言有一個語句'code',後跟'{',後面跟着一堆我沒有興趣解析的代碼,接着是'}' 。我非常希望有一個類似的規則:ANTLR4解析規則以匹配打開/關閉括號

skip_code: 'code' '{' ~['}']* '}'

..這隻會直接跳到右大括號。問題在於被跳過的代碼本身可能會有一對花括號。所以,我基本上需要做的是運行一個計數器並在每個'{'上遞增並在每個'}'上遞減,並且當計數器回到0時結束解析規則。

什麼是最好的方式這在ANTLR4?我應該在檢測到「代碼」時跳過自定義函數併吞下代碼並運行我的計數器,或者在語法中有一些優雅的方式來表達它?

編輯:一些示例代碼,根據要求:

class foo; 
    int m_bar; 
    function foo_bar; 
    print("hello world"); 
    endfunction 
    code { 
    // This is some C code 
    void my_c_func() { 
     printf("I have curly braces {} in a string!"); 
    } 
    } 
    function back_to_parsed_code; 
    endfunction 
endclass 
+0

你能發表一個你解析的代碼的真實例子嗎? –

+0

在您想要忽略的代碼塊內是否有字符串文字(可能包含'{'或'}')?這些代碼塊中是否有註釋(可能包括''''或'}')?你可以選擇Mike的建議,但在lexing期間丟棄這些代碼塊可能會更容易。在解析器中放棄它們意味着'{...}'中的所有內容都需要被標記。 –

+0

@BartKiers是的,大括號內的內容可以被認爲是完全合法的C代碼,帶有自己的字符串,花括號等等,這使得詞法分析器很難做到。理想情況下,我甚至不希望對該代碼進行標記,但是Mike的建議確實使其在解析器中非常容易實現。關於如何在詞法分析器中完成的任何建議? – Stan

回答

3

我會使用類似:

skip_code: CODE_SYM block; 
block: OPEN_CURLY (~CLOSE_CURLY | block)* CLOSE_CURLY; 

CODE_SYM: 'code'; 
OPEN_CURLY: '{'; 
CLOSE_CURLY: '}'; 
1

我在詞法分析處理這些代碼塊。一個快速演示:

import org.antlr.v4.runtime.ANTLRInputStream; 
import org.antlr.v4.runtime.Token; 

public class Main { 

    public static void main(String[] args) { 

     String source = "class foo;\n" + 
       " int m_bar;\n" + 
       " function foo_bar;\n" + 
       "  print(\"hello world\");\n" + 
       " endfunction\n" + 
       " code {\n" + 
       "  // This is some C code }}} \n" + 
       "  void my_c_func() {\n" + 
       "  printf(\"I have curly braces {} in a string!\");\n" + 
       "  }\n" + 
       " }\n" + 
       " function back_to_parsed_code;\n" + 
       " endfunction\n" + 
       "endclass"; 

     System.out.printf("Tokenizing:\n\n%s\n\n", source); 

     DemoLexer lexer = new DemoLexer(new ANTLRInputStream(source)); 

     for (Token t : lexer.getAllTokens()){ 
      System.out.printf("%-20s '%s'\n", 
        DemoLexer.VOCABULARY.getSymbolicName(t.getType()), 
        t.getText().replaceAll("[\r\n]", "\\\\n") 
      ); 
     } 
    } 
} 

如果你運行上面的類,下面將要印:

Tokenizing: 

class foo; 
    int m_bar; 
    function foo_bar; 
    print("hello world"); 
    endfunction 
    code { 
    // This is some C code }}} 
    void my_c_func() { 
     printf("I have curly braces {} in a string!"); 
    } 
    } 
    function back_to_parsed_code; 
    endfunction 
endclass 

ID     'class' 
ID     'foo' 
ANY     ';' 
ID     'int' 
ID     'm_bar' 
ANY     ';' 
ID     'function' 
ID     'foo_bar' 
ANY     ';' 
ID     'print' 
ANY     '(' 
STRING    '"hello world"' 
ANY     ')' 
ANY     ';' 
ID     'endfunction' 
ID     'code' 
BLOCK    '{\n  // This is some C code }}} \n  void my_c_func() {\n  printf("I have curly braces {} in a string!");\n  }\n }' 
ID     'function' 
ID     'back_to_parsed_code' 
ANY     ';' 
ID     'endfunction' 
ID     'endclass' 
0

您可以使用modes你的目的。請注意CODE部分的兩種模式。 Yoy只能使用一種模式無法正確關閉CODE部分。

詞法

lexer grammar Question_41355044Lexer; 

CODE: 'code'; 
LCURLY: '{' -> pushMode(CODE_0); 
WS: [ \t\r\n] -> skip; 

mode CODE_0; 

CODE_0_LCURLY: '{' -> type(OTHER), pushMode(CODE_N); 
RCURLY: '}' -> popMode;  // Close for LCURLY 
CODE_0_OTHER: ~[{}]+ -> type(OTHER); 

mode CODE_N; 

CODE_N_LCURLY: '{' -> type(OTHER), pushMode(CODE_N); 
CODE_N_RCURLY: '}' -> type(OTHER), popMode; 
OTHER: ~[{}]+; 

分析器

parser grammar Question_41355044Parser; 

options { tokenVocab = Question_41355044Lexer; } 

skip_code: 'code' LCURLY OTHER* RCURLY; 

輸入

code { 
    // This is some C code 
    void my_c_func() { 
     printf("I have curly braces {} in a string!"); 
    } 
} 

個輸出令牌

CODE LCURLY({) OTHER( // Th...) OTHER({) OTHER(  pr...) 
OTHER({) OTHER(}) OTHER(in a st...) OTHER(}) OTHER() RCURLY(}) EOF 

同樣的方法被用於ANTLR語法解析本身:https://github.com/antlr/grammars-v4/tree/master/antlr4

但是運行時代碼LexerAdaptor.py來代替兩電平模式存在。