当前位置: 首页 > 知识库问答 >
问题:

Antlr4中的字符串插值

潘宪
2023-03-14

我有一种使用模式进行字符串插值的语法:大致如下:

lexer grammar Example;

//default mode tokens
LBRACE: '{' -> pushMode(DEFAULT_MODE);
RBRACE: '}' -> popMode;

OPEN_STRING: '"' -> pushMode(STRING);
mode STRING;
ID_INTERPOLATION: '$' IDEN;
OPEN_EXPR_INTERPOLATION: '${' -> pushMode(DEFAULT_MODE);
TEXT: '$' | (~[$\r\n])+;
CLOSE_STRING: '"' -> popMode;
parser grammar ExampleParser;
options {tokenVocab = Example;}

test: string* EOF;
string: OPEN_STRING string_part* CLOSE_STRING;
string_part: TEXT | ID_INTERPOLATION | OPEN_EXPR_INTERPOLATION expr RBRACE;


//more rules that use LBRACE and RBRACE

现在这工作和标记一切主要是我想要的,但它确实有2个缺陷。

  1. 如果RBRACES的数量过多,它会弹出第一个默认模式,这会使IDE出现故障,而不仅仅是显示错误。
  2. 关闭块和关闭插值的标记是相同的,因此我无法根据需要突出显示它们。(这是主要的)

我的IDE仅基于令牌突出显示,所以这是一个问题,我希望能够以不同的方式突出显示它们。所以基本上我想要一个解决方案,当RBRACE在字符串中时,它将成为不同的令牌。

我更喜欢不使用语义谓词,因为我不想把它束缚在一种语言上,但如果需要的话,我可以接受,我可能需要更多的解释,因为我没有太多使用它们。

共有2个答案

许高峻
2023-03-14

因此,我着手实现一个内插字符串解析器,只使用ANTLR代码(不使用宿主语言代码块)。我发现这很有效,包括嵌套插值字符串。。。

lexer grammar Lexer;

LeftBrace: '{';
RightBrace: '}' -> popMode;

Backtick: '`' -> pushMode(InterpolatedString);
Integer: [0-9]+;
Plus: '+';

mode InterpolatedString;

EscapedLeftBrace: '\\{' -> type(Grapheme);
EscapedBacktick: '\\`' -> type(Grapheme);
ExprStart: '{' -> type(LeftBrace), pushMode(DEFAULT_MODE);
End: '`' -> type(Backtick), popMode;
Grapheme: ~('{' | '`');
parser grammar Parser;

options {
    tokenVocab = Lexer;
}

startRule: expression EOF;

interpolatedString: Backtick (Grapheme | interpolatedStringExpression)* Backtick;

interpolatedStringExpression: LeftBrace expression RightBrace;

expression
    : expression Plus expression
    | atom
    ;
    
atom: Integer | interpolatedString;

您可以使用输入进行测试

`{`{`{`{`{`{`{`hello world`}`}`}`}`}`}`}`
匡晟
2023-03-14

感谢@sepp2k帮助我解决问题。

这有点像黑客,但它正是我所需要的

我通过将RBRACE上的popMode更改为以下方式解决了此问题:

RBRACE: '}' {
    if(_modeStack.size() > 0) {
        popMode();
        if(_mode != DEFAULT_MODE) {
            setType(EXPR_INTERPOLATION);
        }
    }
};

我还将解析器更改为

string_part: TEXT | ID_INTERPOLATION | EXPR_INTERPOLATION expr EXPR_INTERPOLATION;

我知道在特定情况下更改令牌类型是非常粗鲁的,但它为我完成了工作,所以我会保留它,除非我找到一种不那么粗鲁的方法来做到这一点。

 类似资料:
  • 在普通字符串中,我可以用反斜杠转义: 在字符串文字中有可能做同样的事情吗?反斜杠不再是转义字符: 到目前为止,我看到的唯一解决方案是字符串连接,这非常难看,以及嵌套插值,这开始变得有点可笑:

  • null null 以下是我的(不完整和不成功的)尝试: 如果不能在lexer中解决这个问题,我可以使用标记、、、、、和自行编写解析器规则。

  • 如果在antlr4 lexer中有一个ONELINE_STRING片段规则标识一行上的一个简单引号字符串,那么如何在lexer中创建一个更通用的字符串规则,该规则将相邻的ONELINE_STRING连接起来(即,只要它们都在不同的行上开始,仅用空格和/或注释分隔)? 即, 将被解析为两个字符串标记,“foo”后跟“bar” 同时: 示例1: Sample3(注意,'output'是该语言中的关键字

  • 问题 你想创建一个字符串,让它包含体现某个 CoffeeScript 变量的文本。 解决方案 使用 CoffeeScript 中类似 Ruby 的字符串插值,而不是 JavaScript 的字符串拼接。 插值: muppet = "Beeker" favorite = "My favorite muppet is #{muppet}!" # => "My favorite muppet is B

  • 我正在尝试编写一个ANTLR语法,用于解析字符串插值表达式,例如: 我得到的错误是: MyParser。g4: MyLemus. g4: 像以下这样的表达式可以正常工作: 知道我做错了什么吗?