Compiler construction 语法分析器的输入标记序列

Compiler construction 语法分析器的输入标记序列,compiler-construction,Compiler Construction,在编译器中,第一阶段创建标记并将其发送到语法分析器 我感到困惑的是,语法分析器在获取所有令牌后启动其进程,或者从一些令牌开始 考虑以下包含两个函数的程序 void fun() { printf("world"); } int main() { printf("hello"); return 0; } 现在,上面的标记如下所示 <keyword, 1> <identifier, 2> <symbols, {> <symbols, (> <sy

在编译器中,第一阶段创建标记并将其发送到语法分析器

我感到困惑的是,语法分析器在获取所有令牌后启动其进程,或者从一些令牌开始

考虑以下包含两个函数的程序

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

现在,令牌将被传递给解析器

在这个场景中,解析器需要两个函数和令牌,否则它将首先完成,然后再执行。还有什么序列标记将被传递给解析器?如果必须按顺序进行,这意味着词法分析器是否需要维护标记的顺序

另一个疑问是为整个程序、函数或复合语句创建的解析树


有人能回答上面的问题吗?

我并不十分清楚您不确定的是什么,但一般来说,编译器可以采取任何一种方式:

lexer可以提前运行,将整个输入文件标记化,然后将标记列表传递给解析器。这就是我碰巧使用的解析器生成器所采用的模式

然而,更常见的方法实际上是解析器根据需要调用lexer以获取新的标记,对于大多数解析器系统,还有一些“unget”命令,以便解析器可以将标记推回lexer,以防它在语法中走错了路径


对于生成解析树的编译器系统,解析树通常包含源文件中的所有内容。当然,在解析树中会有函数的自包含子树,在那些复合语句子树中,等等,这取决于被解析的语言。

目前,我正在构建一个编译器

scanner对象(scanner将源文件划分为令牌)提供给解析器。在scanner中,应该有一个获取nexttoken的方法。 解析器在需要时调用scanner.getnexttoken()。 例如,Scanner类如下所示

现在让我们从解析器的角度来看,我将用一个例子来解释。 让我们分析声明intx语法规则是变量声明-->类型说明符标识符半类型说明符可以是int或void

上面的解析器只解析如下声明

  • int x
  • int-y 如果正确或错误,则返回true。 关于解析树,解析树的构造在以下阶段非常有帮助。在语法分析期间删除一些不必要的标记后,基本上是将源文件作为树结构传递。 所以应该为整个程序构建语法树。如果你想了解更多的技术细节,你可以对此发表评论。我很乐意回答


    这意味着对于一个程序,只有一个解析树。是否正确?假设该程序适合单个编译单元,是的。@500-内部服务器错误-很好的答案。这意味着一个程序即使有多个函数和全局声明,也只能得到一个解析树
    public class Scanner {
    public TokenType getToken()
        {
           //Logic to divide text into tokens.
    
           return Token;
        }
    }
    
    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;
           }
    
        }