2016-12-28 2 views
3

Я разбираю язык, на котором есть оператор 'code', за которым следует '{', за которым следует куча кода, который у меня нет интереса к синтаксическому разбору, а затем '}' , Я бы в идеале хотелось бы иметь правила, как:ANTLR4 правило синтаксического разбора для сопоставления открытых/закрытых скобок

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

..which бы просто пропустить вперед к закрывающей фигурной скобкой. Проблема в том, что пропущенный код сам может иметь пары фигурных скобок. Итак, что мне нужно сделать, это запустить счетчик и увеличить каждый «{» и декремент на каждом «}» и закончить правило разбора, когда счетчик вернулся к 0.

Каков наилучший способ сделать это в ANTLR4? Должен ли я перейти к пользовательской функции, когда «код» обнаружен и проглотил токены и запустил мой счетчик, или есть какой-то элегантный способ выразить это в самой грамматике?

EDIT: Некоторые примеры кода, в соответствии с просьбой:

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

Существуют ли строковые литералы (которые могут включать '{' или '}') внутри блока кода, который вы хотите игнорировать? Есть ли комментарии внутри этих блоков кода (которые могут включать '{' или '}')? Вы могли бы пойти на предложение Майка, но отбросить эти кодовые блоки во время лексинга может быть проще. Отбрасывание их в синтаксическом анализаторе означало бы, что все внутри '{...}' все равно нужно будет обозначить. –

+0

@BartKiers Да, контент в фигурных скобках можно считать полностью законным кодом C, с его собственными строками, фигурными фигурными скобками и т. Д., Что делает его сложнее сделать в lexer. В идеале я не хочу даже маркировать этот код, но предложение Майка делает его очень простым для реализации в синтаксическом анализаторе.Любые предложения о том, как это можно сделать в лексере? – 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

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 используется там вместо режимов два уровня.

Смежные вопросы