我试图用Verilog语言解析标识符。完整的语法是here。
他们可以使用以下表格:
name
name[index]
name[start:stop]
name[index][start:stop]
name.(any of the above)
name[index].(any of the above)
name[index].name[index]... .name[index][start:stop]
或以EMBF格式:
(name ([index])?)+ ([start:stop])?
此处name
是大多数编程语言中的典型标识符,而index
,start
和stop
是整数。
我是yacc的新手(我实际上正在使用Jison),但我不确定单一超前令牌限制是否可以正确解释这一点。如果name
和[
在堆栈中,则无法区分索引和开始之间的区别。
到目前为止,这是我的语法:
primary
: number
| hierarchical_identifier bracketted_range_expression
| hierarchical_identifier
;
primary
: number
| hierarchical_identifier
| hierarchical_identifier bracketted_range_expression
;
hierarchical_identifier
: IDENTIFIER
| IDENTIFIER '[' UNSIGNED_NUMBER ']'
| hierarchical_identifier '.' IDENTIFIER
| hierarchical_identifier '.' IDENTIFIER '[' UNSIGNED_NUMBER ']'
;
bracketted_range_expression
: '[' range_expression ']';
range_expression
: UNSIGNED_NUMBER ':' UNSIGNED_NUMBER
这会产生几个shift / reduce和reduce / reduce错误,并且它根本不想解析某些行foo[1:0]
。它期望]
代替:
。有办法解决这个问题吗?
答案 0 :(得分:1)
您的分析是正确的。根据您的语法,在解析器开始扫描hierarchical_identifier
之前必须减少bracketed_range_expression
,但无法知道[
后的IDENTIFIER
是否会启动bracketed_range_expression
(在这种情况下,减少是必要的)或[
'[' UNSIGNED_NUMBER ']'
(在这种情况下应该移位)。
使用bison,我们可以使用GLR解析器来解决这个问题,但是使用jison我们只能使用LALR(1)。幸运的是,语言仍然是LALR(1);所需要的只是通过扩展一些非终结符并在以后减少它们来推迟转移/减少决策。
不幸的是,结果有点难看,因为它需要一定量的重复。因为我们需要始终能够转移[
,所以我们最终会对语法进行“非规范化”(从数据库设计中借用一个术语)。
这是一个使用the jison on-line tool测试的解决方案。 (这些操作仅用于显示语法将范围附加到整个分层列表,而不仅仅是列表中的最后一个标识符。)
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
[0-9]+ return 'NUMBER'
[a-zA-Z][a-zA-Z0-9]* return 'IDENTIFIER'
. return yytext[0]
<<EOF>> return 'EOF'
/lex
%start expr
%% /* language grammar */
expr : primary EOF { return $1; }
;
primary: NUMBER
| hierarchical_identifier
| hierarchical_identifier_with_range
;
indexed_identifier
: IDENTIFIER '[' NUMBER ']' { $$ = { "id": $1, "idx": $3}; } ;
postfix_range
: '[' NUMBER ':' NUMBER ']' { $$ = [ $2, $4 ]; } ;
hierarchical_identifier
: IDENTIFIER { $$ = []; $$.push({ "id": $1}); }
| indexed_identifier { $$ = [ $1 ]; }
| hierarchical_identifier '.' IDENTIFIER
{ $$ = $1; $$.push({ "id": $3}); }
| hierarchical_identifier '.' indexed_identifier
{ $$ = $1; $$.push($3); }
;
hierarchical_identifier_with_range
: IDENTIFIER postfix_range
{ $$ = { "idlist": [{"id": $1}],
"lo": $2[0], "hi": $2[1]}; }
| indexed_identifier postfix_range
{ $$ = { "idlist": [$1],
"lo": $2[0], "hi": $2[1]}; }
| hierarchical_identifier '.' IDENTIFIER postfix_range
{ $1.push({"id": $3});
$$ = { "idlist": $1,
"lo": $4[0], "hi": $4[1]}; }
| hierarchical_identifier '.' indexed_identifier postfix_range
{ $1.push($3);
$$ = { "idlist": $1,
"lo": $4[0], "hi": $4[1]}; }
;
如果您最终计划使用bison,您可能会发现GLR解析器更容易,而不会增加太多的解析开销(因为您的语法确实是明确的)。