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

不在给定点读取特定标记

费明诚
2023-03-14

在语法文件中的某个时候,我希望ANTLR将我的输入读取为2个标记,而不是一个。在我的源文件中,我有

12345.name

Lexer消耗了

12345.

作为浮动标记。在源文件中的这个特定点上,我希望ANTLR将其读取为

  • 12345(内景)
  • 。(点)
  • 姓名(name)

有没有办法告诉ANTLR它应该在某个给定点忽略浮点类型?

这是我的电流。g4文件:

grammar Quest;
import Lua;

@header {
package dev.codeflush.m2qc.antlr;
}

/*
prefixed everything with "m2" to avoid nameclashes
*/

m2QuestFile
    : m2Define* m2Quest* EOF
    ;

m2Define
    : 'define' NAME m2DefineValue
    ;

m2DefineValue
    : ~('\r\n' | '\r' | '\n')
    ;

m2Quest
    : 'quest' NAME 'begin' m2State* 'end'
    ;

m2State
    : 'state' NAME 'begin' (m2TriggerBlock | m2Function)* 'end'
    ;

m2TriggerBlock
    : 'when' m2Trigger ('or' m2Trigger)* ('with' exp)? 'begin' block 'end'
    ;

m2Function
    : 'function' NAME funcbody
    ;

m2Trigger
    : m2TriggerTarget DOT m2TriggerEvent DOT m2TriggerSubEvent DOT m2TriggerArgument
    | m2TriggerTarget DOT m2TriggerEvent DOT m2TriggerArgument
    | m2TriggerTarget DOT m2TriggerEvent
    | m2TriggerEvent
    ;

m2TriggerTarget
    : NAME
    | INT
    | NORMALSTRING
    ;

/*
not complete
*/
m2TriggerEvent
    : 'button'
    | 'enter'
    | 'info'
    | 'item_informer'
    | 'kill'
    | 'leave'
    | 'letter'
    | 'levelup'
    | 'login'
    | 'logout'
    | 'unmount'
    | 'target'
    | 'chat'
    | 'timer'
    | 'server_timer'
    ;

m2TriggerSubEvent
    : 'click'
    | 'chat'
    | 'arrive'
    ;

m2TriggerArgument
    : exp
    ;

DOT
    : '.'
    ;

我用的是https://github.com/antlr/grammars-v4/blob/master/lua/Lua.g4的Lua语法

我当前的示例输入文件如下所示:

quest test begin
    state start begin
        when kill begin
        end

        when "12345".kill begin
        end

        when 12345.kill begin
        end
    end
end

其中前两个按预期工作,但第三个不工作(因为lexer读取“12345.”作为一个浮点标记)

共有1个答案

董昕
2023-03-14

我在语法上也有类似的需求,我想在特定条件下(这里:当一个点后面紧跟着一个标识符,包括一个关键字)为一个匹配发出多个标记(实际上是2个)。

// Special rule that should also match all keywords if they are directly preceded by a dot.
// Hence it's defined before all keywords.
// Here we make use of the ability in our base lexer to emit multiple tokens with a single rule.
DOT_IDENTIFIER:
    DOT_SYMBOL LETTER_WHEN_UNQUOTED_NO_DIGIT LETTER_WHEN_UNQUOTED* { emitDot(); } -> type(IDENTIFIER)
;

需要一个助手函数来发出额外的令牌:

/**
 * Puts a DOT token onto the pending token list.
 */
void MySQLBaseLexer::emitDot() {
  _pendingTokens.emplace_back(_factory->create({this, _input}, MySQLLexer::DOT_SYMBOL, _text, channel,
                                               tokenStartCharIndex, tokenStartCharIndex, tokenStartLine,
                                               tokenStartCharPositionInLine));
  ++tokenStartCharIndex;
}

这反过来需要对令牌生产进行自定义处理。您必须覆盖令牌流中的nextToken方法,以便在返回下一个真正的令牌之前考虑挂起的令牌列表。

/**
 * Allow a grammar rule to emit as many tokens as it needs.
 */
std::unique_ptr<antlr4::Token> MySQLBaseLexer::nextToken() {
  // First respond with pending tokens to the next token request, if there are any.
  if (!_pendingTokens.empty()) {
    auto pending = std::move(_pendingTokens.front());
    _pendingTokens.pop_front();
    return pending;
  }

  // Let the main lexer class run the next token recognition.
  // This might create additional tokens again.
  auto next = Lexer::nextToken();
  if (!_pendingTokens.empty()) {
    auto pending = std::move(_pendingTokens.front());
    _pendingTokens.pop_front();
    _pendingTokens.push_back(std::move(next));
    return pending;
  }
  return next;
}

请记住:lexer规则仍然会发出自己的令牌(我在此处将其设置为IDENTIFIER),这意味着您只需发出额外的令牌。

 类似资料:
  • 我的Firebase RealtimeDatabase包含一个名为Records在该表中有FirebaseUser Uid,在每个Uid中有日期,在每个日期中有一个产品列表。这是一个来自firebase控制台的示例。 在一个名为DailyTableActivity的活动中,有一个提示到DatePickerDialog的按钮和一个ListView元素,该元素应该为连接的用户显示对话框中特定日期(或当

  • 所以我正在写一个代码来获取scanf一个文本文件并返回一个格式化的文本消息日志。我一直在想,当文件扫描行“332982000 20555552002 205551001 7 Webb先生,我能问你一个问题吗?”时,如何在某一点扫描文件中的字符串,并打印E.X点以外的所有字符串我将前4个数字扫描为整数,并将其余写入的文本扫描到从“Mr.Webb”开始的字符数组中。 我尝试使用一个for循环与fsca

  • 有谁能帮助我阅读作为Web服务调用响应的XML吗。 我得到的回应是这样的: 当我得到-1作为响应时,我想预先执行动作。我如何阅读它。我在GAE中使用struts,我使用

  • 问题内容: 我有一个包含100行的CSV文件。 如何读取特定行? 我想读第9行或第23行等? 问题答案: 您可以使用来过滤文件,如下所示:

  • 我在使用OPENCSV并尝试从一行中读取特定列时遇到了小问题。我有一个看起来像这样的csv文件 现在我只想读取第2列和第3列(名称和名称2)。 我的代码看起来像这样 我已经尝试手动将“i”变量设置为1和2。但是我得到了日志中显示的4个相同的结果。缺少什么?谢谢!

  • 问题内容: 我正在使用for循环读取文件,但是我只想读取特定的行,例如26号和30号行。是否有任何内置功能可实现此目的? 问题答案: 如果要读取的文件很大,并且你不想一次读取内存中的整个文件: 注意,对于nth行。 在Python 2.6或更高版本中: