解析键/值子参数
Parsing key / value subparameters
我对如何解析(或多或少)“自由形式”参数列表有点无能为力,假设语法允许
PARM=(VAL1, 'VAL2', VAL3, KEY4=VAL4, KEY5=VAL5(XYZ), PARM=ABC, SOMETHING=ELSE)
我已经设法基本上解析了位置参数和 key/value 参数的组合,但是一旦我遇到像 PARM= 这样的词法分析器标记,解析器就会用“不匹配的输入”退出,我不能特别允许或期望任何东西,因为传递给函数的这些参数是完全任意的。
所以我想我需要切换到特定的词法分析器模式,但现在我看不到如何正确切换回“正常”模式,分隔符是 PARM=( 在左边和右侧的结束 ),但由于“数据”本身可以包含(成对的)括号,我如何识别正确的结束括号,这样我就不会过早地结束词法分析器模式?
TIA - 亚历克斯
编辑 1:
显示关键字在不应该使用的地方出现问题的最小语法,因为这是复杂语法的一部分,我无法更改标记的顺序以将 ID 放在其他所有内容的前面,例如,作为它会抓住太多。所以我看不出如果不进入不同的词法分析器模式,它是如何工作的。
lexer grammar ParmLexer;
SPACE : [ \t\r\n]+ -> channel(HIDDEN) ;
COMMA : ',' ;
EQUALS : '=' ;
LPAREN : '(' ;
RPAREN : ')' ;
PARM : 'PARM=' ;
ID : ID_LITERAL ;
fragment ID_LITERAL : [A-Za-z]+ ;
.
parser grammar ParmParser;
options { tokenVocab=ParmLexer; }
parms : PARM LPAREN parm+ RPAREN ;
parm : (pkey=ID EQUALS)? pval=ID COMMA? ;
输入:
PARM=( TEST, KEY=VAL, PARM=X)
结果
line 1:22 extraneous input 'PARM=' expecting {')', ID}
您的 parm
规则中没有可识别 PARM
标记的规则(替代)。
Bart 使用 Lexer 模式提供了答案(并假设 LPAREN
和 RPAREN
始终控制这些模式),但您也可以只设置一个匹配所有关键字的解析器规则:
lexer grammar ParmLexer
;
SPACE: [ \t\r\n]+ -> channel(HIDDEN);
COMMA: ',';
EQUALS: '=';
LPAREN: '(';
RPAREN: ')';
PARM: 'PARM';
KW1: 'KW1';
KW2: 'KW2';
ID: ID_LITERAL;
fragment ID_LITERAL: [A-Za-z]+;
parser grammar ParmParser
;
options {
tokenVocab = ParmLexer;
}
parms: PARM EQUALS LPAREN parm (COMMA parm)* RPAREN;
parm: ((pkey = ID | kwid = kw) EQUALS)? pval = ID;
kw: PARM | KW1 | KW2;
输入
"PARM=( TEST, KEY=VAL, KW2=v2, PARM=X)"
产量:
(parms PARM = ( (parm TEST) , (parm KEY = VAL) , (parm (kw KW2) = v) , (parm (kw PARM) = X) ))
So I'd think I'll need to switch to a specific lexer mode but right now I can't see how I would properly switch back to "normal" mode
而不是切换到模式(使用 -> mode(...)
),您可以将“特殊”模式压入堆栈(使用 -> pushMode(...)
),然后在遇到 )
时弹出来自堆栈的模式。这样,您可以有多个嵌套列表 (..(..(..).)..)
。快速演示:
lexer grammar ParmLexer;
SPACE : [ \t\r\n]+ -> channel(HIDDEN);
EQUALS : '=' ;
LPAREN : '(' -> pushMode(InList);
PARM : 'PARM';
ID : [A-Za-z] [A-Za-z0-9]*;
mode InList;
LST_LPAREN : '(' -> type(LPAREN), pushMode(InList);
RPAREN : ')' -> popMode;
COMMA : ',';
LST_EQUALS : '=' -> type(EQUALS);
STRING : '\'' ~['\r\n]* '\'';
LST_ID : [A-Za-z] [A-Za-z0-9]* -> type(ID);
LST_SPACE : [ \t\r\n]+ -> channel(HIDDEN);
和:
parser grammar ParmParser;
options { tokenVocab=ParmLexer; }
parse
: PARM EQUALS list EOF
;
list
: LPAREN ( value ( COMMA value )* )? RPAREN
;
value
: ID
| STRING
| key_value
| ID list
;
key_value
: ID EQUALS value
;
它将像这样解析您的示例输入 PARM=(VAL1, 'VAL2', VAL3, KEY4=VAL4, KEY5=VAL5(XYZ), PARM=ABC, SOMETHING=ELSE)
:
我对如何解析(或多或少)“自由形式”参数列表有点无能为力,假设语法允许
PARM=(VAL1, 'VAL2', VAL3, KEY4=VAL4, KEY5=VAL5(XYZ), PARM=ABC, SOMETHING=ELSE)
我已经设法基本上解析了位置参数和 key/value 参数的组合,但是一旦我遇到像 PARM= 这样的词法分析器标记,解析器就会用“不匹配的输入”退出,我不能特别允许或期望任何东西,因为传递给函数的这些参数是完全任意的。
所以我想我需要切换到特定的词法分析器模式,但现在我看不到如何正确切换回“正常”模式,分隔符是 PARM=( 在左边和右侧的结束 ),但由于“数据”本身可以包含(成对的)括号,我如何识别正确的结束括号,这样我就不会过早地结束词法分析器模式?
TIA - 亚历克斯
编辑 1:
显示关键字在不应该使用的地方出现问题的最小语法,因为这是复杂语法的一部分,我无法更改标记的顺序以将 ID 放在其他所有内容的前面,例如,作为它会抓住太多。所以我看不出如果不进入不同的词法分析器模式,它是如何工作的。
lexer grammar ParmLexer;
SPACE : [ \t\r\n]+ -> channel(HIDDEN) ;
COMMA : ',' ;
EQUALS : '=' ;
LPAREN : '(' ;
RPAREN : ')' ;
PARM : 'PARM=' ;
ID : ID_LITERAL ;
fragment ID_LITERAL : [A-Za-z]+ ;
.
parser grammar ParmParser;
options { tokenVocab=ParmLexer; }
parms : PARM LPAREN parm+ RPAREN ;
parm : (pkey=ID EQUALS)? pval=ID COMMA? ;
输入:
PARM=( TEST, KEY=VAL, PARM=X)
结果
line 1:22 extraneous input 'PARM=' expecting {')', ID}
您的 parm
规则中没有可识别 PARM
标记的规则(替代)。
Bart 使用 Lexer 模式提供了答案(并假设 LPAREN
和 RPAREN
始终控制这些模式),但您也可以只设置一个匹配所有关键字的解析器规则:
lexer grammar ParmLexer
;
SPACE: [ \t\r\n]+ -> channel(HIDDEN);
COMMA: ',';
EQUALS: '=';
LPAREN: '(';
RPAREN: ')';
PARM: 'PARM';
KW1: 'KW1';
KW2: 'KW2';
ID: ID_LITERAL;
fragment ID_LITERAL: [A-Za-z]+;
parser grammar ParmParser
;
options {
tokenVocab = ParmLexer;
}
parms: PARM EQUALS LPAREN parm (COMMA parm)* RPAREN;
parm: ((pkey = ID | kwid = kw) EQUALS)? pval = ID;
kw: PARM | KW1 | KW2;
输入
"PARM=( TEST, KEY=VAL, KW2=v2, PARM=X)"
产量:
(parms PARM = ( (parm TEST) , (parm KEY = VAL) , (parm (kw KW2) = v) , (parm (kw PARM) = X) ))
So I'd think I'll need to switch to a specific lexer mode but right now I can't see how I would properly switch back to "normal" mode
而不是切换到模式(使用 -> mode(...)
),您可以将“特殊”模式压入堆栈(使用 -> pushMode(...)
),然后在遇到 )
时弹出来自堆栈的模式。这样,您可以有多个嵌套列表 (..(..(..).)..)
。快速演示:
lexer grammar ParmLexer;
SPACE : [ \t\r\n]+ -> channel(HIDDEN);
EQUALS : '=' ;
LPAREN : '(' -> pushMode(InList);
PARM : 'PARM';
ID : [A-Za-z] [A-Za-z0-9]*;
mode InList;
LST_LPAREN : '(' -> type(LPAREN), pushMode(InList);
RPAREN : ')' -> popMode;
COMMA : ',';
LST_EQUALS : '=' -> type(EQUALS);
STRING : '\'' ~['\r\n]* '\'';
LST_ID : [A-Za-z] [A-Za-z0-9]* -> type(ID);
LST_SPACE : [ \t\r\n]+ -> channel(HIDDEN);
和:
parser grammar ParmParser;
options { tokenVocab=ParmLexer; }
parse
: PARM EQUALS list EOF
;
list
: LPAREN ( value ( COMMA value )* )? RPAREN
;
value
: ID
| STRING
| key_value
| ID list
;
key_value
: ID EQUALS value
;
它将像这样解析您的示例输入 PARM=(VAL1, 'VAL2', VAL3, KEY4=VAL4, KEY5=VAL5(XYZ), PARM=ABC, SOMETHING=ELSE)
: