Строковая интерполяция: это возможно без добавления членов? - PullRequest
0 голосов
/ 06 ноября 2018

Я хотел бы создать парсер Antlr для пользовательского языка и решил в качестве примера выбрать простой калькулятор . В моей новой грамматике должно быть возможно определить строку, как это:

s = "Hello, I am a string"

и обрабатывать интерполяцию строк. Текст в двойных кавычках, заключенный в persent, должен рассматриваться как интерполированный, например,

s = "Hello, did you know that %2 + 2% is 4?"

Двойной знак процента не должен обрабатываться, например,

s = "He wants 50%% of this deal."

Но в то же время мой калькулятор должен поддерживать работу модуля:

x = 5 % 2

Пока что мне удалось создать лексер / грамматику, которая могла бы переключать режим и анализировать простые строки, вот они:

lexer grammar CalcLexer;

EQ: '=';
PLUS: '+';
MINUS: '-';
MULT: '*';
DIV: '/';

LPAREN : '(' ;
RPAREN : ')' ;

SINGLE_PERCENT_POP: '%' -> popMode;

ID  :   [a-zA-Z]+ ;
INT :   [0-9]+ ;

OPEN_DOUBLE_QUOTE: '"' -> pushMode(STRING_MODE);

NEWLINE:'\r'? '\n' ;
WS  :   [ \t]+ -> skip;


mode STRING_MODE;
DOUBLE_PERCENT: '%%';
SINGLE_PERCENT: '%' -> pushMode(DEFAULT_MODE);
TEXT: ~('%'|'\n'|'"')+;


CLOSE_DOUBLE_QUOTE: '"' -> popMode;

и

parser grammar CalcGrammar;

options { tokenVocab=CalcLexer; } // use tokens from CalcLexer.g4

prog:   stat+ ;

stat:   expr NEWLINE
    |   ID EQ (expr|text) NEWLINE
    |   NEWLINE
    ;

text: OPEN_DOUBLE_QUOTE content* CLOSE_DOUBLE_QUOTE;

content: DOUBLE_PERCENT | TEXT | SINGLE_PERCENT expr SINGLE_PERCENT_POP;

expr:   expr (MULT|DIV) expr
    |   expr (PLUS|MINUS) expr
    |   INT
    |   ID
    |   LPAREN expr RPAREN
    ;

Но единственное, что не работает, и я не уверен, что когда-либо возможно реализовать без пользовательского кода (членов), это операция модуля:

x = 5 % 2

Нет способа попросить Anltr проверить предыдущий режим и безопасный поп-режим. Но я надеюсь, что мое понимание неверно, и есть какой-то способ трактовать знак % как оператор в режиме по умолчанию?

Я нашел несколько источников вдохновения, возможно, они вам тоже помогут:

1 Ответ

0 голосов
/ 06 ноября 2018

Закон Мерфи для StackOverflow: вы найдете ответ на свой вопрос через несколько минут, когда вы отправите подробный вопрос в SO .

Вместо переключения на DEFAULT_MODE я должен создать отдельный - STRING_INTERPOLATION. Таким образом, я должен определить отдельные токены для этого режима, который позволит использовать знак % в обычном режиме (и запретить в интерполированном).

Вот лексер и грамматика, которая работает для меня:

lexer grammar CalcLexer;

EQ: '=';
PLUS: '+';
MINUS: '-';
MULT: '*';
DIV: '/';
MOD: '%';

LPAREN : '(' ;
RPAREN : ')' ;

ID  : F_ID;
INT : F_INT;

fragment F_ID: [a-zA-Z]+ ;
fragment F_INT: [0-9]+ ;

OPEN_DOUBLE_QUOTE: '"' -> pushMode(STRING_MODE);

NEWLINE:'\r'? '\n' ;
WS  :   [ \t]+ -> skip;


mode STRING_MODE;
DOUBLE_PERCENT: '%%';
SINGLE_PERCENT: '%' -> pushMode(STRING_INTERPOLATION);
TEXT: ~('%'|'\n'|'"')+;


CLOSE_DOUBLE_QUOTE: '"' -> popMode;

mode STRING_INTERPOLATION;
SINGLE_PERCENT_POP: '%' -> popMode;

I_PLUS: PLUS -> type(PLUS);
I_MINUS: MINUS -> type(MINUS);
I_MULT: MULT -> type(MULT);
I_DIV: DIV -> type(DIV);
I_MOD: MOD -> type(MOD);

I_LPAREN: LPAREN -> type(LPAREN);
I_RPAREN: RPAREN -> type(RPAREN);

I_ID  : F_ID -> type(ID);
I_INT : F_INT -> type(INT);

WS1  :   [ \t]+ -> skip;

и

parser grammar CalcGrammar;

options { tokenVocab=CalcLexer; } // use tokens from CalcLexer.g4

prog:   stat+ ;

stat:   expr NEWLINE
    |   ID EQ (expr|text) NEWLINE
    |   NEWLINE
    ;

text: OPEN_DOUBLE_QUOTE content* CLOSE_DOUBLE_QUOTE;

content: DOUBLE_PERCENT | TEXT | SINGLE_PERCENT expr SINGLE_PERCENT_POP;

expr:   expr (MULT|DIV|MOD) expr
    |   expr (PLUS|MINUS) expr
    |   INT
    |   ID
    |   LPAREN expr RPAREN
    ;

Надеюсь, это кому-нибудь поможет. Возможно, будущее меня.

...