用于解析 PHP 类语言的语法,以便它可以处理语法中的 PHP 开始和结束标记(“<?”和“?>”)

Grammar for parsing PHP like language such that it can handle the PHP begin and end tokens ("<?" and "?>") in the grammar

我试图理解如何定义类似 PHP 的语法。在 PHP 中,可以退出 PHP 模式进入 HTML 模式,然后返回 PHP 模式。

为了问这个问题,我正在定义我的 PHP-like 语言 简单得可笑。在下面这个问题的剩余部分中,这种语言将被称为 "PHP-like"。

它只包含一个构造:if (expression) { block_list },即 if 语句。 block_list 是一系列嵌套的 if 语句, 表达式或 HTMLs。同样,为了使语言简单得可笑,一个 表达式必须是标识符。

这是一个示例,显示了该语言的有效代码。这里 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-like 模式之外的东西)输出为一个标记,即整个 HTML 块是一个标记。它不输出空白。它不会在每个类似 PHP 的模式中输出开始 <? 和结束 ?>,即它不会输出第一次出现的 BEGIN 和下一次出现的 END。一旦到达 END,其后的任何内容都会再次被解析为 HTML,直到下一次出现 BEGIN。

因此,对于这个问题中的第二个代码示例,词法分析器输出这个。

代码:

<?  if (expression1) {     ?>
        some html here
<?      if (expession2) { ?>
            some html here
<?      } 
    }
?>

词法分析器输出:

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
    }
?>

我有两个问题。

  1. 如果词法分析器输出 BEGIN 和 END 标记,我该如何编写语法来处理它们?
  2. 是否最好不要输出 BEGIN 和 END 标记,以便语法保持简单?

假设您的词法分析器继续是有状态的,因此将为 ENDBEGIN 之间的文本发出单个 HTML 标记,语法上几乎没有区别.

除了第一个和最后一个 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 */