我已经让项目使用任何编程语言制作语法分析器。我是用C#做的。已经创建了简单的上下文无关语法。但现在我非常混淆为语法分析器制作算法。
语法就是这样:
Namespace var . { class }
Class var . { method } . class | null
Method function | null
Function return_type.var.(function_arguements).{.stmt_list.} . Method
.......... and so on
我必须显示错误和错误的行号。我需要一些指导才能开始编码。我尝试了2D数组,链表,枚举,结构。但我无法为此创建任何好的算法。
答案 0 :(得分:2)
当我使用编译器时,我们必须为简单语言编写编译器。我不知道你是否在你的问题中完全按照你的语言定义或者你已经达到了多远,但这是我们在解析语言时使用的方法。
首先,您需要一个词法分析器类,它只负责获取输入中的下一个标记。这基本上是通过代码进行的,每次调用时,GetNextToken()
都会返回代码中的下一个字符串。所以说你有以下代码:
PROCEDURE sum() RETURN INTEGER;
第一次调用GetNextToken()
会返回PROCEDURE
。第二个调用将返回sum
,第三个调用将返回(
,然后返回)
,然后返回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()
,其工作方式与Program()
相同,然后查看您之后是否有.
。
关键是在每个结尾标记处,例如;
,您将拥有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;
}
我现在看到这是很多东西。我不确定这是否是教练要求你采取的方法,但我发现如果你理解你的语言,它很简单易行。我不保证这是最有效或最有效的方法,只需要我使用的方法。
我真的希望我能正确理解你的问题......