构建一个逐字符读取的词法分析器?

时间:2012-06-01 23:23:12

标签: php lexer

我正在用PHP构建一个基本词法分析器,就像练习一样。现在我正在制作lex PHP源代码和输出通过HTML标签突出显示来源,但我使用的是真正的令牌名称和内容,而不仅仅是一些广泛的正则表达式匹配。

我设置它的方法是逐字逐句地读入PHP源代码。它检查当前字符以确定当前令牌可能的内容,然后读入与适当模式匹配的下一个 x 字符。

例如,如果当前字符是“,我将读取所有字符,直到遇到另一个字符”,之前没有转义\。这是一个不好的方式吗?我见过和理解的唯一另一种方法是创建一个编译大量正则表达式并且同时匹配所有标记的类,但这对我来说似乎并不灵活。

思想?

    $str = '';

    $php = str_replace( "\r\n", "\n", $php );
    $php = str_split( $php );
    $len = count( $php );
    $keyword = '';

    for ( $i = 0; $i < $len; $i++ ) {
        $char = $php[$i];

        // Detect PHP strings and backtick execution operators
        if ( strpos( self::STRING_CHARACTERS, $char ) !== FALSE ) {
            $string         = $char;
            $opening_quote  = $char;
            $escaped        = FALSE;

            while ( isset( $php[++$i] ) && ( $escaped || $php[$i] != $opening_quote ) ) {
                $string .= $php[$i];

                if ( $php[$i] == '\\' ) {
                    $escaped = !$escaped;
                }
            }

            $string .= $php[$i];

            if ( $opening_quote == "'" ) {
                $str .= '<span class="php-string php-single-quoted-string">' . htmlspecialchars( $string ) . '</span>';
            } else if ( $opening_quote == '"' ) {
                $str .= '<span class="php-string php-double-quoted-string">' . htmlspecialchars( $string ) . '</span>';
            } else if ( $opening_quote == '`' ) {
                $str .= '<span class="php-execution-operator php-backtick">' . htmlspecialchars( $string ) . '</span>';
            }
            continue;
        }

        $str .= $char;
    }

2 个答案:

答案 0 :(得分:2)

如果您打算将其作为手写工具,那么请务必继续使用当前的方法。

如果您正在编写flex或ANTLR等工具,那么巨大的匹配引擎方法非常棒,并且您希望能够为各种语言整天构建高效的解析器。但是如果你只想解析一种语言,这是一项额外的努力。

答案 1 :(得分:1)

典型的手写方法是创建正则表达式或自动机列表。您在列表中运行,并且第一个元素与输入中的当前位置成功匹配,为您提供下一个标记和分类。您可以使用通过当前字符限制列表的地图来加快速度。

如果你想变得更加漂亮,可以将自动机组合成一个巨大的自动机,但通常会使用一个工具。

您可能对https://class.coursera.org/提供的免费斯坦福编译器课程感兴趣。