2016-10-15 5 views
-1

Я использую ANTLR4 для анализа некоторого «упрощенного» исходного кода C-стиля. Моя грамматика выглядит следующим образом:Соответствие до конца функции

grammar Language; 

script: (include)* (functionDefinition)* EOF; 

include: '#include' Blank FilePath Semicolon; 

functionName: FileName; 

functionDefinition: functionName '(' parameters ')' '{' functionBody '}'; 

functionBody: .*?; // This needs fixing 

parameter: FileName; 

parameters: parameter (',' Blank parameter)*; 

FileName: AlphaCharacter WordCharacter*; 

FilePath: FileName ChildFilePath*; 

ChildFilePath: PathSlash FileName; 

PathSlash: ForwardSlash | BackwardSlash; 

ForwardSlash: '/'; 

BackwardSlash: '\\'; 

AlphaCharacter: [a-zA-Z]; 

WordCharacter: [a-zA-Z_0-9]; 

Blank: ' '; 

Whitespace: (' ' | '\t' | '\r' | '\n'); 

Semicolon: ';'; 

SkipWhitespaces: Whitespace+ -> skip; 

Учитывая следующий ввод текста:

#include testWz/fdrf675tr\a56s; 
#include testWz/fdrftr\s; 

func1(param, par) 
{ 
    if(true) 
    { 
     whatever(); 
    } 
} 

func2() 
{ 

} 

Я реализовал следующий посетитель, чтобы видеть, что происходит:

public class ListenerPrinter extends LanguageBaseListener 
{ 
    @Override 
    public void enterInclude(LanguageParser.IncludeContext context) 
    { 
     System.out.println("[INCLUDE] " + context.FilePath().getText()); 
    } 

    @Override 
    public void enterFunctionDefinition(LanguageParser.FunctionDefinitionContext definition) 
    { 
     LanguageParser.ParametersContext parameters = definition.parameters(); 
     System.out.println("[FUNCTION DEFINITION] " + definition.getText()); 
     System.out.println("[PARAMETERS] " + parameters.getText()); 
     System.out.println("[BODY] " + definition.functionBody().getText()); 
    } 
} 

Я хотел бы, чтобы правильно определить конечно, функциональные тела, не разбивая их на свои компоненты, так как это намного больше. До сих пор следующий вывод производится:

[INCLUDE] testWz/fdrf675tr\a56s 
[INCLUDE] testWz/fdrftr\s 
[FUNCTION DEFINITION] func1(param, par){if(true){whatever();}}func2(){} 
[PARAMETERS] param, par 
[BODY] if(true){whatever();}}func2(){ 

Тело функции слишком длинный и включает в себя определение следующей функции, а также. Одна из идей заключалась бы в обнаружении следующей закрывающей скобки + количества открытых скобок, найденных между ними, но я не уверен, как это сделать с помощью грамматических правил.

+0

Предоставляет ли ваша «упрощенная» C возможность содержать вложенные {...}? Вы подразумеваете, что фраза * обнаруживает ... количество открытых скобок, найденных между *. Если это так, простое регулярное выражение не может подобрать тело функции, поскольку регулярные выражения не могут совпадать с произвольными скобками. Если нет, ваш упрощенный C нереалистичен, и непонятно, что вы узнаете, выполняя это упражнение на нереалистичном языке, и вы сможете использовать его где-то еще. –

+0

@IraBaxter: Это не нереалистичный язык, поскольку он существует как скриптовый движок. Кроме того, я не уверен, что вы имеете в виду с вложенными {...}, поскольку существуют обычные циклы 'if' и' while', но нет функции, вложенной в другую функцию, которая была бы довольно необычной в любом случае – BullyWiiPlaza

+0

. Вам разрешено иметь вложенные { ...}? например, если c {... если d {} ...}? Это очень распространено. Язык, который их не позволяет, очень необычен. –

ответ

-1

functionBody - это правило совпадения. Нежелательный модификатор здесь не помогает, поскольку само правило не имеет завершающего токена. Так что попробуйте удалить его и вместо того, чтобы поставить подстановочное соответствие в functionDefinition правилу:

functionDefinition: functionName '(' parameters ')' '{' .*? '}'; 

или альтернативно переместить фигурные скобки к functionBody правилу:

functionDefinition: functionName '(' parameters ')' functionBody; 
functionBody: OpenCurly .*? CloseCurly; 

Примечания: Я использовал правила LeXeR для кудрявого скобки по намерениям. Рекомендуется определять все лексеры-маркеры в собственных правилах вместо неявно в правилах парсера (избегая таких проблем, как множественные определения, автоматически назначенные имена токенов и т. Д.).


UPDATE

Я не знал, искомое решение должно поддерживать вложенные блоки, ограниченные в фигурных скобках (весь вопрос может понадобиться немного полировки, поэтому есть 3 близкие голоса). Общий принцип решения состоит в том, что вы определяете одно или несколько правил, которые явно определяют пару фигурных скобок, так что правило (ы) согласовывается только в том случае, если открывающая и закрывающая фигурные скобки сбалансированы. Вы можете сделать это следующим образом:

functionBody: OpenCurly .*? (functionBody .*?)? CloseCurly; 

т.е. рекурсивно определить functionBody как содержащий себя.

+0

. Оба ваших предложения по-прежнему дают одинаковый (неверный) результат, поэтому, возможно, мне все еще нужно все описать?Но это не должно быть необходимо :( – BullyWiiPlaza

+0

@MikeLischke: OP сообщает нам, что {...} в его языке гнездо сколь угодно глубокое. Вы используете регулярное выражение, чтобы попытаться совместить тело функции, найдя внешнюю {}. Чистые регулярные выражения не может распознать вложенные parenthese любого вида, поэтому этот ответ не может быть прав. –

+0

@ IraBaxter да, вы правы. Я обновил свой ответ –

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