我试图理解如何定义类似PHP的语法。在PHP中,可以退出PHP模式进入HTML模式,然后再进入PHP模式。
为了提出这个问题,我正在定义类似PHP的语言 太荒谬了。在下面这个问题的其余部分中,这种语言将被称为“类似PHP”。
它只包含一个构造:if (expression) { block_list }
,即
if语句。 block_list是嵌套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>
这是另一个例子,展示了我们如何在if语句中脱离类似PHP的模式进入HTML模式。
<? if (expression1) { ?>
some html here
<? if (expession2) { ?>
some html here
<? }
}
?>
为了实现这一点,我有一个能够识别以下标记的词法分析器。
HTML = All characters from the beginning of the code or the last
occurrence of "?>" to the end of the code or the next
occurrence of "<?". Zero length string is allowed.
IDENTIFIER = [_a-zA-Z][_a-zA-Z0-9]* i.e. C identifier, a sequence
of underscores, letters and
digits such that the first
character is not a digit.
WHITESPACE = [ \t\r\n]+ i.e. a sequence of spaces, tabs
and newlines.
BEGIN = "<?"
END = "?>"
IF = "if"
LPAREN = "("
RPAREN = ")"
LBRACE = "{"
RBRACE = "}"
词法分析器输出每个HTML块(即类似PHP的模式之外的东西)作为标记,即整个HTML块是单个标记。它不输出WHITESPACE。它不会在每个类似PHP的模式下输出开始<?
和结束?>
,即它不输出第一次出现的BEGIN和下一次出现的END。一旦达到END,其后面的任何内容将再次被解析为HTML,直到下一次出现BEGIN。
因此,对于这个问题中的第二个代码示例,词法分析器输出它。
代码:
<? if (expression1) { ?>
some html here
<? if (expession2) { ?>
some html here
<? }
}
?>
Lexer输出:
HTML ""
IF "if"
LPAREN "("
IDENTIFIER "expression1"
RPAREN ")"
LBRACE "{"
HTML "\n some html here\n"
IF "if"
LPAREN "("
...
不输出BEGIN和END标记使解析器语法简单。现在我可以使用以下语法解析这些令牌。由于解析器不必处理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;
但是,我想在词法分析器中输出BEGIN和END标记。有没有一种很好的方法来为它编写语法,以便它处理嵌套的if语句,这些语句中也可能包含HTML?
我正在尝试在以下语法中处理词法分析器输出中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
}
?>
我有两个问题。
答案 0 :(得分:2)
假设你的词法分析器仍然是有状态的,那么HTML
和END
之间的文本会发出一个BEGIN
标记,语法几乎没有差别。< / p>
除了第一个和最后一个HTML
令牌之外,每个其他HTML
令牌前面都会有END
,后面跟BEGIN
。换句话说,我们有:
html: END HTML BEGIN;
轻微的复杂性是我们需要处理第一个和最后一个HTML
令牌,这意味着我们需要一个新的非终端(它将是起始符号):
program: HTML BEGIN block_list END HTML;
语法的其余部分与原始语法相同,只是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;
如果关联文本为空字符串,新词法分子不再发出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 */