flex + bison,具有不同语法的部分
flex+bison, sections with different syntaxes
我正在使用 flex & bison 开发一个解析器,它应该解析具有不同语法的不同部分的源代码。
想想 php,它只是 "stupidly" 转储所有内容,直到找到
<?php
,然后它进入实际解析内容的句法部分,当它找到 ?>
时,它会返回转储。
所以当我在 "dumping" 部分时,扫描仪应该只提供原始字符串。有意义的标记(WHILE、OPENPARENTHESIS、IDENTIFIER 等)只能在句法部分中提供,并且 \ 开始句法部分。
我发现你可以给不同的 flex 规则 "start conditions",
所以我基本上可以在不同的扫描仪之间切换,比如
%x semantic
%x dump
%%
<dump>"\" { BEGIN(semantic); }
<dump>. { (*yylval).stringvalue = yytext; return yy::parser::token::CHAR;}
<semantic>"while" {return yy::parser::token::WHILE;}
这正是我所需要的。
我的问题是句法部分的结尾不能用正则表达式来描述,所以这个决定不能在扫描器内完成,它必须由解析器来完成。我基本上希望它回到转储模式 "in between rules"。所以我想做一些像
CODEELEMENT: FOR OPEN STATEMENT SEMICOLON BOOL SEMICOLON STATEMENT CLOSE <<GO TO DUMP MODE>> ELEMENT
你可能会说,这应该成为 C 中 for 循环之类的规则,但是 "body"(ELEMENT)应该再次被读取为转储(这将提供只有一个字符,除非您再次将多个字符与 { 和 } 组合在一起)
我知道 bison 可以执行代码 "in between rules",我尝试声明一个全局变量(呃)"dumpmode",像这样将 {dumpmode = true;} 放入规则中
CODEELEMENT: FOR OPEN STATEMENT SEMICOLON BOOL SEMICOLON STATEMENT CLOSE {dumpmode = true;} ELEMENT
并放
if(dumpmode)
{
BEGIN(dump);
dumpmode = false;
}
在 flex 规则前面(这与我在上面链接的页面上的示例相似)
但这是行不通的,它实际上是有道理的 - AFAIK bison 已经需要最终的 ELEMENT 令牌来决定使用该规则(因此代码不会在令牌到来之前执行),但这个令牌只会由转储模式生成,该模式在该过程中此时未激活。
你知道这样做的方法吗?在规则之间从 bison 代码切换 flexer 的启动条件?也许我需要像
这样打破野牛规则
CODEELEMENT: FOR1 FOR2
;
FOR1: FOR OPEN STATEMENT SEMICOLON BOOL SEMICOLON STATEMENT CLOSE {dumpmode = true;}
;
FOR2: ELEMENT
;
但我认为这种方法不适用于 if-then-else 结构...
您是否尝试过函数 void yy_pop_state ()
,从 Bison 部分调用它?
我正在使用 flex & bison 开发一个解析器,它应该解析具有不同语法的不同部分的源代码。
想想 php,它只是 "stupidly" 转储所有内容,直到找到
<?php
,然后它进入实际解析内容的句法部分,当它找到 ?>
时,它会返回转储。
所以当我在 "dumping" 部分时,扫描仪应该只提供原始字符串。有意义的标记(WHILE、OPENPARENTHESIS、IDENTIFIER 等)只能在句法部分中提供,并且 \ 开始句法部分。
我发现你可以给不同的 flex 规则 "start conditions", 所以我基本上可以在不同的扫描仪之间切换,比如
%x semantic
%x dump
%%
<dump>"\" { BEGIN(semantic); }
<dump>. { (*yylval).stringvalue = yytext; return yy::parser::token::CHAR;}
<semantic>"while" {return yy::parser::token::WHILE;}
这正是我所需要的。
我的问题是句法部分的结尾不能用正则表达式来描述,所以这个决定不能在扫描器内完成,它必须由解析器来完成。我基本上希望它回到转储模式 "in between rules"。所以我想做一些像
CODEELEMENT: FOR OPEN STATEMENT SEMICOLON BOOL SEMICOLON STATEMENT CLOSE <<GO TO DUMP MODE>> ELEMENT
你可能会说,这应该成为 C 中 for 循环之类的规则,但是 "body"(ELEMENT)应该再次被读取为转储(这将提供只有一个字符,除非您再次将多个字符与 { 和 } 组合在一起)
我知道 bison 可以执行代码 "in between rules",我尝试声明一个全局变量(呃)"dumpmode",像这样将 {dumpmode = true;} 放入规则中
CODEELEMENT: FOR OPEN STATEMENT SEMICOLON BOOL SEMICOLON STATEMENT CLOSE {dumpmode = true;} ELEMENT
并放
if(dumpmode)
{
BEGIN(dump);
dumpmode = false;
}
在 flex 规则前面(这与我在上面链接的页面上的示例相似)
但这是行不通的,它实际上是有道理的 - AFAIK bison 已经需要最终的 ELEMENT 令牌来决定使用该规则(因此代码不会在令牌到来之前执行),但这个令牌只会由转储模式生成,该模式在该过程中此时未激活。
你知道这样做的方法吗?在规则之间从 bison 代码切换 flexer 的启动条件?也许我需要像
这样打破野牛规则CODEELEMENT: FOR1 FOR2
;
FOR1: FOR OPEN STATEMENT SEMICOLON BOOL SEMICOLON STATEMENT CLOSE {dumpmode = true;}
;
FOR2: ELEMENT
;
但我认为这种方法不适用于 if-then-else 结构...
您是否尝试过函数 void yy_pop_state ()
,从 Bison 部分调用它?