我正在创建自己的语法,到目前为止我只有基元类型。然而,现在我想通过引用添加一个新的类型,数组,其格式类似于Java或C#,但我遇到了无法使其与ANTLR一起工作的问题。
我正在使用的代码示例与此类似:
VariableDefinition
{
id1: string;
anotherId: bool;
arrayVariable: string[5];
anotherArray: bool[6];
}
MyMethod()
{
temp: string[3];
temp2: string;
temp2 = "Some text";
temp[0] = temp2;
temp2 = temp[0];
}
Lexer包含:
BOOL: 'bool';
STRING: 'string';
fragment DIGIT: [0-9];
fragment LETTER: [[a-zA-Zu0080-u00FF_];
fragment ESCAPE : '\"' | '\\' ; // Escape 2-char sequences: " and \
LITERAL_INT: DIGIT+;
LITERAL_STRING: '"' (ESCAPE|.)*? '"' ;
OPEN_BRACKET: '[';
CLOSE_BRACKET: ']';
COLON: ':';
SEMICOLON: ';';
ID: LETTER (LETTER|DIGIT)*;
我的Parser将是这个的扩展(有更多的规则和其他表达式,但我不认为这与这个场景有关系(:
global_
: GLOBAL '{' globalVariables+=variableDefinition* '}'
;
variableDefinition
: name=ID ':' type=type_ ';'
;
type_
: referenceType # TypeReference
| primitiveType # TypePrimitive
;
primitiveType
: BOOL # TypeBool
| CHAR # TypeChar
| DOUBLE # TypeDouble
| INT # TypeInteger
| STRING # TypeString
;
referenceType
: primitiveType '[' LITERAL_INT ']' # TypeArray
;
expression_
: identifier=expression_ '[' position=expression_ ']' # AccessArrayExpression
| left=expression_ operator=( '*' | '/' | '%') right=expression_ # ArithmeticExpression
| left=expression_ operator=( '+' | '-' ) right=expression_ # ArithmeticExpression
| value=ID # LiteralID
我试过:
- 在示例程序中的不同词素之间放置空格,以防lexer出现问题。(没有任何变化(
- 在type_中创建一个名为arrayType的规则,在arrayType引用type_(由于左递归而失败:ANTLR显示以下错误
The following sets of rules are mutually left-recursive [type_, arrayType]
- 将基元类型和引用类型放入一个规则中
type_
: BOOL # TypeBool
| CHAR # TypeChar
| DOUBLE # TypeDouble
| INT # TypeInteger
| STRING # TypeString
| type_ '[' LITERAL_INT ']' # TypeArray
;
- 结果:·使用空格分隔数组(
temp: string [5] ;
(
line 23:25 missing ';' at '[5'
line 23:27 mismatched input ']' expecting {'[', ';'}
·没有空白(temp: string[5];
(。
line 23:18 mismatched input 'string[5' expecting {BOOL, 'char', 'double', INT, 'string'}
line 23:26 mismatched input ']' expecting ':'
编辑1:这是在尝试生成我给出的示例时树的样子:分析树检查器
fragment LETTER: [[a-zA-Zu0080-u00FF_];
您允许[
作为字母(从而作为标识符中的字符(,因此在string[5]
中,string[5
被解释为标识符,这使得解析器认为后续的]
没有匹配的[
。类似地,在string [5]
中,[5
被解释为一个标识符,这使得解析器看到两个连续的标识符,这也是不允许的。
要解决此问题,您应该从LETTER
中删除[
。
作为一般提示,当得到您不理解的解析错误时,您应该尝试查看正在生成的令牌以及它们是否符合您的预期。
对于那些希望灵活处理空白的语言来说,有一个规则是很常见的,比如
WS: [ trn]+ -> skip; // or channel(HIDDEN)
它应该能解决你的问题。
这会将空白区转移到一边,这样您就不必在解析器规则中关注它了。
如果没有这种方法,您仍然需要定义一个空白规则(与上面的模式相同(,但是,如果您不skip
它(或将它发送到HIDDEN
通道(,则必须通过插入WS?
将它包含在您想要允许空白的任何位置。很明显,这可能会变得非常乏味(并且会给语法和生成的解析树增加很多"噪音"(。