将带有空格的单词作为一个标记进行匹配,但不允许使用某些关键字标记
match words with spaces as one token but disallow certain keyword tokens
我有以下令牌规则:
IF: 'IF' | 'if';
THEN: 'THEN' | 'then';
ELSE: 'ELSE' | 'else';
BINARYOPERATOR: 'AND' | 'and' | 'OR' | 'or';
NOT: 'NOT' | 'not';
WORD: (DIGIT* (LOWERCASE | UPPERCASE | WORDSYMBOL)) (LOWERCASE | UPPERCASE | DIGIT | WORDSYMBOL)*;
这是有效的,其中 my variable
之类的结果是 WORD WORD
。我希望能够只有一个令牌,它代表了整个事物。
我把它挂到:
IF: 'IF' | 'if';
THEN: 'THEN' | 'then';
ELSE: 'ELSE' | 'else';
BINARYOPERATOR: 'AND' | 'and' | 'OR' | 'or';
NOT: 'NOT' | 'not';
WORD: (LOWERCASE | UPPERCASE | WORDSYMBOL)+ (' '* (LOWERCASE | UPPERCASE | WORDSYMBOL))*;
这解决了这个问题,但它也捕获了我想如上所述归类为关键字标记的字符串。
例如 if my variable then something
不应该只是一个单一的 WORD
标记,它应该是 IF WORD THEN WORD
.
我明白为什么要按原样对其进行标记(首选使用更多输入的标记),但我不确定如何更改行为。
不幸的是(对于你想做的),ANTLR 的标记化不是这样工作的。
(这更像是一个“合乎逻辑”的解释,而不是实际的实现)
当 ANTLR 正在评估 Lexer 规则时,它会尝试将每个规则与输入流中的字符相匹配,从您在该输入流中的当前位置开始。
一旦它拥有所有匹配的输入序列,如果有一个序列比其余序列长,它将选择产生最长令牌的令牌类型。这是您的 WORD
规则将消耗输入的地方,直到找到与 WORD
中的字符不匹配的内容(如果它们与 WORD
模式).
(为了完整性)如果 Tokenizer 找到多个等长匹配项,则语法中匹配的第一个规则将是分配的令牌类型。
您可能会通过以下方法获得成功:
假设:WORD
不能是您的语言关键字之一
- 确保
WORD
规则位于所有关键字规则之后,以便它们优先。
- 添加解析器规则
word: WORD+;
- 现在在任何你会使用
RULE
标记的地方使用 word
解析器规则。
- 编写一个覆盖
enterWord()
的监听器并将所有 WORD
合并为一个“单词”。 (您可以通过多种方式处理此步骤,但这是一种相当简单的方法)
注意事项:
- 语言通常不允许这样做是有原因的。我怀疑你会在路上遇到其他 complications/ambiguities。
- 性能可能受到影响,因为 ANTLR 必须做更多的前瞻性工作才能知道何时回溯。
我有以下令牌规则:
IF: 'IF' | 'if';
THEN: 'THEN' | 'then';
ELSE: 'ELSE' | 'else';
BINARYOPERATOR: 'AND' | 'and' | 'OR' | 'or';
NOT: 'NOT' | 'not';
WORD: (DIGIT* (LOWERCASE | UPPERCASE | WORDSYMBOL)) (LOWERCASE | UPPERCASE | DIGIT | WORDSYMBOL)*;
这是有效的,其中 my variable
之类的结果是 WORD WORD
。我希望能够只有一个令牌,它代表了整个事物。
我把它挂到:
IF: 'IF' | 'if';
THEN: 'THEN' | 'then';
ELSE: 'ELSE' | 'else';
BINARYOPERATOR: 'AND' | 'and' | 'OR' | 'or';
NOT: 'NOT' | 'not';
WORD: (LOWERCASE | UPPERCASE | WORDSYMBOL)+ (' '* (LOWERCASE | UPPERCASE | WORDSYMBOL))*;
这解决了这个问题,但它也捕获了我想如上所述归类为关键字标记的字符串。
例如 if my variable then something
不应该只是一个单一的 WORD
标记,它应该是 IF WORD THEN WORD
.
我明白为什么要按原样对其进行标记(首选使用更多输入的标记),但我不确定如何更改行为。
不幸的是(对于你想做的),ANTLR 的标记化不是这样工作的。
(这更像是一个“合乎逻辑”的解释,而不是实际的实现)
当 ANTLR 正在评估 Lexer 规则时,它会尝试将每个规则与输入流中的字符相匹配,从您在该输入流中的当前位置开始。
一旦它拥有所有匹配的输入序列,如果有一个序列比其余序列长,它将选择产生最长令牌的令牌类型。这是您的 WORD
规则将消耗输入的地方,直到找到与 WORD
中的字符不匹配的内容(如果它们与 WORD
模式).
(为了完整性)如果 Tokenizer 找到多个等长匹配项,则语法中匹配的第一个规则将是分配的令牌类型。
您可能会通过以下方法获得成功:
假设:WORD
不能是您的语言关键字之一
- 确保
WORD
规则位于所有关键字规则之后,以便它们优先。 - 添加解析器规则
word: WORD+;
- 现在在任何你会使用
RULE
标记的地方使用word
解析器规则。 - 编写一个覆盖
enterWord()
的监听器并将所有WORD
合并为一个“单词”。 (您可以通过多种方式处理此步骤,但这是一种相当简单的方法)
注意事项:
- 语言通常不允许这样做是有原因的。我怀疑你会在路上遇到其他 complications/ambiguities。
- 性能可能受到影响,因为 ANTLR 必须做更多的前瞻性工作才能知道何时回溯。