Parsing 分析每行以特定符号开头的块
我需要解析一段代码,如下所示:Parsing 分析每行以特定符号开头的块,parsing,yacc,lalr,Parsing,Yacc,Lalr,我需要解析一段代码,如下所示: * Block | Line 1 | Line 2 | ... 这很容易做到: block : head lines; head : '*' line; lines : lines '|' line | '|' line ; 现在我想知道如何添加嵌套块,例如: * Block | Line 1 | * Subblock | | Line 1.1 | | ... | Line 2 | ... 这可以用LALR语法表示吗 当然,我可以解
* Block
| Line 1
| Line 2
| ...
这很容易做到:
block : head lines;
head : '*' line;
lines : lines '|' line
| '|' line
;
现在我想知道如何添加嵌套块,例如:
* Block
| Line 1
| * Subblock
| | Line 1.1
| | ...
| Line 2
| ...
这可以用LALR
语法表示吗
当然,我可以解析顶级块,然后再次运行解析器来处理每个顶级块。不过,我只是在学习这个话题,所以避免这种做法对我来说很有趣。这个答案实际上是一条评论(…我的评论很难阅读) 如果您编写一个显式的块结束标记,事情就会变得更清楚
*Block{
|Line 1
*SubBlock{
| line 1.1
| line 1.2
}
|Line 2
|...
}
语法也变得简单了
block : '*' ID '{' lines '}'
lines : lines '|' line
| lines block
|
嵌套块语言不是上下文无关的[注2],因此无法使用LALR(k)解析器对其进行解析 然而,嵌套括号语言当然是上下文无关的,通过替换词法扫描器中的初始|序列,将输入转换为插入形式相对容易。转换很简单:
- 当| s的初始序列比前一行长时,插入
。(初始序列必须正好长一个|;否则可能是语法错误。)BEGIN_块
- 当| s的初始序列比前一行短时,插入足够的
s以使预期长度达到正确值END_块
- 这些|本身不会传递给解析器
INDENT
/DEDENT
策略非常相似。主要区别在于,这里我们不需要一堆缩进级别
转换完成后,语法将如下所示:
content: /* empty */
| content line
| content block
block : head BEGIN_BLOCK content END_BLOCK
| head
head : '*' line
flex实现的大致轮廓如下:(参见下面的注释1)
%x缩进内容
%%
静态整型深度=0,新整型深度=0;
/*处理挂起的结束块*/
发送结束:
如果(新深度<深度){
--深度;
返回端块;
}
^“|”[[:blank:][]*{new_depth=1;BEGIN(INDENT);}
^.{new_depth=0;yyless(0);BEGIN(CONTENT);
转到发送_end;}
^\n/*忽略空行*/
{
“|”[[:blank:][]*++新深度;
.{yyless(0);开始(内容);
如果(新深度>深度){
++深度;
if(new_depth>depth){/*报告语法错误*/}
返回开始块;
}否则就要发送完;
}
\n BEGIN(首字母);/*也许您关心这一空行*/
}
/*把你在这里使用的词汇扫描行*/
{
\n开始(初始);
}
笔记:
depth
和new\u depth
)是本地静态变量这一事实使得lexer不可重入且不可重启(出错后)。这只对玩具代码有用;对于任何实际情况,都应该使词法扫描程序重新进入,并将状态变量放入extra
数据结构中
bar prefix
的实例产生相同的| s字符串。在这种情况下,由于效果实际上是句法上的,因此推迟到以后的语义分析将无法解决解析问题。上下文敏感的其他示例是“句法”还是“语法”“语义”是一场辩论,它产生了惊人的热量,却没有对讨论投下太多的光您所展示的示例有一个不清楚的endoblock(语法会变得奇怪,因为“| |”staff。一些带有eofBlock标记的东西,比如*Block{1.1行*SubBlock{1.1.2行}| 2行|…}会更容易…如果您采用这种方法,您将拥有一种完全不同的语言:)而且
*
和|
符号根本就没有必要,因为{
和}
就足够了。@rici,我知道;这就是为什么我说这是一个注释(一种讨论注释的sintax语言替代方案很酷!(通常在我的Lexer中,我包含一个待返回的标记队列)+1对不起,extra
数据结构是flex提供的变量吗?
%x INDENT CONTENT
%%
static int depth = 0, new_depth = 0;
/* Handle pending END_BLOCKs */
send_end:
if (new_depth < depth) {
--depth;
return END_BLOCK;
}
^"|"[[:blank:]]* { new_depth = 1; BEGIN(INDENT); }
^. { new_depth = 0; yyless(0); BEGIN(CONTENT);
goto send_end; }
^\n /* Ignore blank lines */
<INDENT>{
"|"[[:blank:]]* ++new_depth;
. { yyless(0); BEGIN(CONTENT);
if (new_depth > depth) {
++depth;
if (new_depth > depth) { /* Report syntax error */ }
return BEGIN_BLOCK;
} else goto send_end;
}
\n BEGIN(INITIAL); /* Maybe you care about this blank line? */
}
/* Put whatever you use here to lexically scan the lines */
<CONTENT>{
\n BEGIN(INITIAL);
}