在编译器中,第一阶段创建令牌并将其发送到语法分析器。
我很困惑他们的语法分析器在获得所有令牌后开始其进程或从一些令牌开始。
考虑以下包含两个函数的程序
void fun()
{
printf("world");
}
int main()
{
printf("hello");
return 0;
}
现在,上面的内容被标记为如下所示
<keyword, 1>
<identifier, 2>
<symbols, {>
<symbols, (>
<symbols, )>
<keyword, 3>
<symbols, (>
<string, 4>
<symbols, )>
<punctuation, ;>
<symbols, }>
<keyword, 5>
<keyword, 6>
<symbols, {>
<symbols, (>
<symbols, )>
<keyword, 7>
<symbols, (>
<string, 8>
<symbols, )>
<punctuation, ;>
<keyword, 9>
<constant,10>
<symbols, }>
现在,Tokens将被传递给解析器。
在这种情况下,解析器需要两个函数令牌,否则它将首先完成并继续执行。还有什么序列标记将传递给解析器?如果它必须按顺序进行,那就意味着词法分析器需要维护令牌序列吗?
另一个疑问是为整个程序或函数或复合语句创建的解析树。
有人可以回答上述问题吗?
答案 0 :(得分:1)
我不清楚你不确定的是什么,但通常编译器可以采用以下两种方式:
词法分析器可以预先运行,对整个输入文件进行标记,然后将标记列表传递给解析器。这就是我碰巧使用的解析器生成器的模式。
然而,更常见的方法实际上是解析器在需要时调用新标记的词法分析器,并且对于大多数解析器系统,还有某种“unget”命令,以便解析器可以将标记推回到lexer,以防它在语法中走错路。
对于生成解析树的编译器系统,解析树通常包含源文件中的所有内容。当然,在该解析树中,将存在用于函数的自包含子树以及这些复合语句子树中的内容,依此类推,具体取决于要解析的语言。
答案 1 :(得分:0)
目前我正在构建一个编译器。
扫描程序对象(扫描程序将源文件划分为标记)提供给解析器。在扫描程序中,应该有一种方法可以获得nexttoken。 并且解析器在需要时调用 scanner.getnexttoken()。 例如,Scanner类看起来像这样。
public class Scanner {
public TokenType getToken()
{
//Logic to divide text into tokens.
return Token;
}
}
现在让我们从Parser方面看一下。我将以一个例子来解释。 让我们解析声明 int x; 语法规则是变量声明----&gt;类型说明符IDENTIFIER SEMI 类型说明符可以是 int或void 。
public class Parser {
private Scanner scanner;
parse(Scanner scanr)
{
scanner=scanr;
parseDeclaration();
}
boolean parseDeclaration()
{
current_token= scanner.getToken();//should be int or void.
if(current_token == INT || current_token == VOID)
{
current_token= scanner.getToken();//should be identifier.
if(current_token == IDENTIFIER){
current_token= scanner.getToken();//should be SEMICOLON.
if(current_token == SEMICOLON)
return true;
else{ //if there is a syntax error.
return false;
}
}
上面的解析器只解析像
这样的声明
如果正确则返回true,否则返回false。 对于解析树,解析树的构造在以下阶段中有很大帮助。在语法分析期间删除一些不必要的令牌后,您基本上将源文件作为树结构传递。 所以语法树应该为整个程序构建。如果你想要更多的技术细节,你可以对此发表评论。我很乐意回复。