Parsing 用于解析类PHP语言的语法,以便它可以处理语法中的PHP开始和结束标记(“lt;”?“和“?”gt;”)
我试图理解如何定义类似PHP的语法。在PHP中,可以从PHP模式进入HTML模式,然后再回到PHP模式 为了问这个问题,我定义了我的PHP语言 简单得可笑。在下面这个问题的剩余部分,这种语言将被称为“类似PHP” 它只包含一个构造:Parsing 用于解析类PHP语言的语法,以便它可以处理语法中的PHP开始和结束标记(“lt;”?“和“?”gt;”),parsing,grammar,context-free-grammar,lexical-analysis,Parsing,Grammar,Context Free Grammar,Lexical Analysis,我试图理解如何定义类似PHP的语法。在PHP中,可以从PHP模式进入HTML模式,然后再回到PHP模式 为了问这个问题,我定义了我的PHP语言 简单得可笑。在下面这个问题的剩余部分,这种语言将被称为“类似PHP” 它只包含一个构造:if(expression){block_list},即。 if语句。block_列表是一系列嵌套的if语句, 表达式或HTML。同样,为了保持语言的简单性,一个 表达式必须是标识符 下面是一个示例,显示了此语言中的有效代码。在这里,HTML后面跟着两个嵌套的if语句
if(expression){block_list}
,即。
if语句。block_列表是一系列嵌套的if语句,
表达式或HTML。同样,为了保持语言的简单性,一个
表达式必须是标识符
下面是一个示例,显示了此语言中的有效代码。在这里,HTML后面跟着两个嵌套的if语句,后面跟着另一个HTML
<body><p>Some HTML text here</p>
<?
if (expression1) {
if (expression2) {
expression3
}
}
?>
</p>Some more HTML text here</p></body>
Lexer输出:
HTML ""
IF "if"
LPAREN "("
IDENTIFIER "expression1"
RPAREN ")"
LBRACE "{"
HTML "\n some html here\n"
IF "if"
LPAREN "("
...
不输出开始和结束标记使解析器语法保持简单。现在,我可以使用以下语法解析这些标记。由于解析器不必处理BEGIN和END标记,因此不必在语法中的任何地方提及它们。它使语法保持简单
block_list = block | block_list block;
block = HTML | if_statement | expression;
if_statement = IF LPAREN expression RPAREN LBRACE block_list RBRACE;
expression = IDENTIFIER;
但是,比方说,我想在lexer中输出BEGIN和END标记。有没有一种好方法可以为它编写语法,这样它就可以处理嵌套的if语句,这些语句中可能也包含HTML
我试图在下面的语法中处理lexer输出中存在的BEGIN和END标记,但是我无法找到一个有效的语法
block_list = block | block_list block;
block = HTML | php_like | code;
php_like = BEGIN code | BEGIN code END;
code = if_statement | expression;
if_statement = IF LPAREN expression RPAREN LBRACE block_list RBRACE |
IF LPAREN expression RPAREN LBRACE END block_list RBRACE |
IF LPAREN expression RPAREN LBRACE END block_list BEGIN RBRACE
expression = IDENTIFIER;
上述语法允许在这个问题中使用上述两个代码示例。但它也允许以下无效代码
<?
if (expression1) {
<? expression2
}
?>
我有两个问题
假设您的lexer仍然是有状态的,因此将为
END
和BEGIN
之间的文本发出一个HTML
标记,语法上几乎没有差异
除了第一个和最后一个HTML
标记外,每隔一个HTML
标记前面都会有END
,后面是BEGIN
。换言之,我们有:
html: END HTML BEGIN;
稍微复杂的是,我们需要处理第一个和最后一个HTML
token,这意味着我们需要一个新的非终端(这将是开始符号):
除了HTML
变成HTML
之外,其余语法与原始语法相同:
block_list = block | block_list block;
block = html /* Change is here */ | if_statement | expression;
if_statement = IF LPAREN expression RPAREN LBRACE block_list RBRACE;
expression = IDENTIFIER;
如果在关联文本为空字符串的情况下,您的新lexer不再发出HTML
标记,则需要两个替代规则:
program: leading_html block_list trailing_html;
leading_html: HTML BEGIN | BEGIN;
trailing_html: END HTML | END;
html: END HTML BEGIN | END BEGIN;
/* Remainder as above */
谢谢你提出了一个聪明的解决方案。我喜欢把
BEGIN
和END
作为html
的一部分,而不改变语法的其余部分。你能告诉我html:htmlbegin | END-htmlbegin | END-html
是否也是一种解决方案吗?如果这也是一个正确的解决方案,那么就不需要一个名为program
@LoneLearner的新的非终端:它可能会工作,但我觉得它错了,因为它允许不应该允许的令牌流(即使扫描器不会产生这样的流,除非它没有按照规范运行)。另外,我认为如果你还想让扫描器在没有HTML文本的情况下不生成HTML标记(但我没有检查,所以我可能错了),那么这将导致移位减少冲突。@LoneLearner:我没有在答案中提到这一点,但事实是,我认为你最初的解决方案更好。开始和结束标记不向语法添加任何内容;扫描器在任何情况下都需要跟踪这两个上下文;因此,上下文切换符号(开始和结束)属于扫描仪。至少,这是我的观点,这就是为什么我没有回答这个问题。
html: END HTML BEGIN;
program: HTML BEGIN block_list END HTML;
block_list = block | block_list block;
block = html /* Change is here */ | if_statement | expression;
if_statement = IF LPAREN expression RPAREN LBRACE block_list RBRACE;
expression = IDENTIFIER;
program: leading_html block_list trailing_html;
leading_html: HTML BEGIN | BEGIN;
trailing_html: END HTML | END;
html: END HTML BEGIN | END BEGIN;
/* Remainder as above */