在某些时候,flex添加了开始条件。我很想知道这个功能是否扩展了flex的匹配令牌的理论能力,或者它是否只是一个实用的解决方案,往往使规则(模式和行动)更短更容易读取。
这里有一些含糊之处,因为在我看来,通过巧妙地使用标志变量,可以在 C 级别模拟开始条件;如果为真,那么没有启动条件的弯曲在功率上与启动条件相同。让我们假设我们不能以这种方式扩展我们的扫描仪,并且所有扫描仪都可以通过模式匹配令牌并回显令牌的名称。在这种情况下,flex扫描仪的WITH启动条件是否可以比没有启动条件的扫描仪更多地标记语言?或者我是否总是可以编写一组规则而没有与启动条件的规则集相同的启动条件?
难以清楚地说出问题,但我希望我能够使其准确而清晰。
答案 0 :(得分:2)
它们有效地允许您使用相同的代码运行多个DFA。另一种看待它的方法是它增加了上下文敏感性。
它在Cobol中已经完成,例如PICTURE字符串的词汇规则与其他语言的完全不同,所以你有
PICTURE { BEGIN S_PICTURE; }
<S_PICTURE>blah { ... BEGIN INITIAL; }
答案 1 :(得分:2)
在我的观点中,开始条件非常棒!这不仅仅是语法糖。
就像在函数中对指令进行分组一样。
注1 :在10个开始条件下,我们可能会将您的问题分成10个较小的“私密”弹性问题。
示例:尝试为没有启动条件的(简化)XML编写词法分析器 - 这并不容易! 定义开始条件(inside_CDATA,inside-begin-tag,...)事情要容易得多。
Note2 :默认情况下,我希望将其视为“灵活处理器的自动机”
对于许多问题,这会产生巨大的差异。
Note3 :如果您使用BEGIN state
%option stack
yy_push_state(new_state)
,而不是仅使用yy_pop_state
。 Flex +堆栈可以处理无上下文的语法。 (好吧,好吧,如果事情变得复杂,请使用yacc)
很容易编写基于flex
语法启发的启动条件堆栈Note4 :启动条件也可以在flex外部更改。 (例如在yacc中)
Note5 :编写代码讲故事!请记住,我们有可以做到的符号 简化您的代码,并清楚地表达您的信息。我们可以这样写:
<a>re {...} //normal
<a,b,c,d>re {...} //multi state instruction
<*>re {...} // all-state instruction
<string>{
re1 {...}
re2 {...}
}
答案 2 :(得分:1)
如果我理解你的问题是正确的,你就会问是否有一个堆栈会增加可识别的语言数量。
据我所知,不是 - 它只是为了简化许多重复性任务(例如嵌套注释或替换字符串中的特殊字符)。您仍然只能使用lex的内置功能识别常规语言。
你仍然可以在C中自己模拟堆栈,并且在规范中增加了复杂性:)
答案 3 :(得分:1)
启动条件本身并不能增加扫描仪的功率。它仍然作为简单的状态转换表实现,或者更准确地实现为由起始条件号索引的表的向量。 [注1]
但是,flex
不包含任何更改开始条件的逻辑。这完成了您的操作,这些操作是用C语言编写的,这是一种图灵完备的编程语言。您没有义务将定义启动条件序列的状态机限制为可以使用有限状态机实现的状态。
例如,众所周知,FSM无法识别带括号的表达式,因此它们不是常规语言。但是,在一个小的存储状态的帮助下,灵活地识别它们是没有问题的;它甚至不必是一个堆栈,因为只需要一个计数器:
%x IN_PAREN
%%
int count = 0;
<INITIAL>[(] BEGIN(IN_PAREN); count++; yymore(); // Note 2
<INITIAL>[)] yyerror("Unbalanced parentheses");
<IN_PAREN>[(] count++; yymore();
<IN_PAREN>[)] if (--count) yymore(); else { BEGIN(INITIAL); return BLOCK; }
<IN_PAREN>[^()]+ yymore();
更准确地说,flex
为每个开始条件使用两个表。如果令牌扫描位于文件的开头或在换行符后面,则使用一个表,而在所有其他情况下使用另一个表。这使得flex易于实现^
零长度断言运算符。如果启动条件没有使用该运算符的模式,则永远不会生成第二个表,但表的向量仍然有两个用于启动条件的槽。
使用yymore()
是为了在外括号之间不断累积文本,这样当遇到右括号并且yylex
返回时,yytext
将是整个括号内的表达