0

我已经给出了使用任何编程语言制作语法分析器的项目。我正在用 C# 做。已经创建了简单的上下文无关语法。但是现在我很困惑为语法分析器制作算法。

语法是这样的:

    Namespace       var . { class }
    Class           var . { method  } . class | null
    Method          function | null
    Function        return_type.var.(function_arguements).{.stmt_list.} . Method
                    .......... and so on

我必须显示错误以及错误的行号。我需要一些指导才能开始编码。我尝试了二维数组、链表、枚举、结构。但我无法为此创建任何好的算法。

4

1 回答 1

2

当我使用编译器时,我们必须为一种简单的语言编写编译器。我不知道我是否在您的问题中完全遵循您的语言定义或您已经走了多远,但这是我们在解析语言时使用的方法。

首先,您需要一个词法分析器类,它只负责获取输入中的下一个标记。这实质上是遍历代码并在每次调用时GetNextToken()返回代码中的下一个字符串。假设您有以下代码行:

PROCEDURE sum() RETURN INTEGER;

第一次调用GetNextToken()将返回PROCEDURE。第二个调用会返回sum,第三个会返回(then )then RETURN, INTEGER, 最后;

现在你需要一个语法解析器。这个想法是您的语言定义最终应该达到一个终止标记。这是我的编译器语言定义的一个小片段:

<program> -> $UNIT <prog-identifier> $SEMICOLON
                   <block> $PERIOD
<block> -> [<label-declaration>]
                   {<variable-dec-sec>}*
                   {<procedure-declaration>}*
                   $LEFTBRACE <statement> {$SEMICOLON <statement>}*
                   $RIGHTBRACE

所以在分析器中我们调用一个函数Program()Program()将获得下一个令牌。如果那个标记是UNIT我们将得到 将调用另一个函数,ProgIdentifier()该函数将再次调用GetNextToken(). ProgramIdentifier()会寻找一个标识符类型。继续前进Program(),看看下一个标记是否是;. 然后调用Block()which 的工作方式Program()与然后看看你是否有一个.after。

关键是在每个结束标记处,例如 ,;你会有一个if语句。所以简单的代码Program()可能看起来像这样:

public int Program()
{
    lex.GetNextToken();
        if (lex.InternalCode == TokenTable.UNIT)
        {
            lex.GetNextToken();
            ProgIdentifier();
            if (lex.InternalCode == TokenTable.SEMICOLON)
            {
                lex.GetNextToken();
                Block();
                if (parseErrors)
                {
                    //Drop out into Statement Level Parsing
                    //Statement Level Parsing just calls Statement() for <statement>
                    //until you have gone through the entire input.
                    //The point is to avoid getting many errors if you are missing a
                    //single token.
                    StatementLevelParse();
                }
                if (lex.InternalCode == TokenTable.PERIOD)
                {
                    lex.GetNextToken();
                    if (lex.EndOfFile)
                    {
                        if (!parseFailed)
                        {
                            //Success
                            echo("Success");
                        }
                        else
                        {
                            echo("Parse Failed");
                        }
                    }
                    else
                    {
                        Error(lex.CurrentLine, 200, false, "Expected End Of File: Found " + lex.NextSymbol);
                    }
                }
                else
                {
                    //Fail. Expected $PERIOD
                    Error(lex.CurrentLine, 200, false, "Expected \".\": Found " + lex.NextSymbol);
                }
            }
            else
            {
                //Fail. Expected $SEMICOLON
                Error(lex.CurrentLine, 200, false, "Expected \";\": Found " + lex.NextSymbol);
            }
        }
        else
        {
            //Fail. Expected $UNIT
            Error(lex.CurrentLine, 200, false, "Expected \"UNIT\": Found " + lex.NextSymbol);
        }
        EchoOutput("LEAVING PROGRAM");
        return 0;
}

我现在看到要阅读的内容很多。我不确定这是否是您的讲师希望您采用的方法,但如果您了解您的语言,我发现它非常简单且易于实施。我不保证这是最有效或最有效的方法,只是我被要求使用的方法。

我真的希望我能正确理解你的问题......

于 2013-03-24T14:33:49.167 回答