gcc中C语言的词法分析是怎么做的?

发布于 2022-09-18 17:48:15 字数 22058 浏览 9 评论 0

版本4.3.0,原以为会使用flex,搜索到一些l文件,看内容不像。上网搜,说会调用c-opts.c中c_common_parse_file,循着这个线索找了下去,最好找到libcpp/lex.c中的_cpp_lex_direct,发现尽然是手动分析。

  1. cpp_token *
  2. _cpp_lex_direct (cpp_reader *pfile)
  3. {
  4.   cppchar_t c;
  5.   cpp_buffer *buffer;
  6.   const unsigned char *comment_start;
  7.   cpp_token *result = pfile->cur_token++;
  8. fresh_line:
  9.   result->flags = 0;
  10.   buffer = pfile->buffer;
  11.   if (buffer->need_line)
  12.     {
  13.       if (pfile->state.in_deferred_pragma)
  14.         {
  15.           result->type = CPP_PRAGMA_EOL;
  16.           pfile->state.in_deferred_pragma = false;
  17.           if (!pfile->state.pragma_allow_expansion)
  18.             pfile->state.prevent_expansion--;
  19.           return result;
  20.         }
  21.       if (!_cpp_get_fresh_line (pfile))
  22.         {
  23.           result->type = CPP_EOF;
  24.           if (!pfile->state.in_directive)
  25.             {
  26.               /* Tell the compiler the line number of the EOF token.  */
  27.               result->src_loc = pfile->line_table->highest_line;
  28.               result->flags = BOL;
  29.             }
  30.           return result;
  31.         }
  32.       if (!pfile->keep_tokens)
  33.         {
  34.           pfile->cur_run = &pfile->base_run;
  35.           result = pfile->base_run.base;
  36.           pfile->cur_token = result + 1;
  37.         }
  38.       result->flags = BOL;
  39.       if (pfile->state.parsing_args == 2)
  40.         result->flags |= PREV_WHITE;
  41.     }
  42.   buffer = pfile->buffer;
  43. update_tokens_line:
  44.   result->src_loc = pfile->line_table->highest_line;
  45. skipped_white:
  46.   if (buffer->cur >= buffer->notes[buffer->cur_note].pos
  47.       && !pfile->overlaid_buffer)
  48.     {
  49.       _cpp_process_line_notes (pfile, false);
  50.       result->src_loc = pfile->line_table->highest_line;
  51.     }
  52.   c = *buffer->cur++;
  53.   LINEMAP_POSITION_FOR_COLUMN (result->src_loc, pfile->line_table,
  54.                                CPP_BUF_COLUMN (buffer, buffer->cur));
  55.   switch (c)
  56.     {
  57.     case ' ': case '\t': case '\f': case '\v': case '\0':
  58.       result->flags |= PREV_WHITE;
  59.       skip_whitespace (pfile, c);
  60.       goto skipped_white;
  61.     case '\n':
  62.       if (buffer->cur < buffer->rlimit)
  63.         CPP_INCREMENT_LINE (pfile, 0);
  64.       buffer->need_line = true;
  65.       goto fresh_line;
  66.     case '0': case '1': case '2': case '3': case '4':
  67.     case '5': case '6': case '7': case '8': case '9':
  68.       {
  69.         struct normalize_state nst = INITIAL_NORMALIZE_STATE;
  70.         result->type = CPP_NUMBER;
  71.         lex_number (pfile, &result->val.str, &nst);
  72.         warn_about_normalization (pfile, result, &nst);
  73.         break;
  74.       }
  75.     case 'L':
  76.       /* 'L' may introduce wide characters or strings.  */
  77.       if (*buffer->cur == '\'' || *buffer->cur == '"')
  78.         {
  79.           lex_string (pfile, result, buffer->cur - 1);
  80.           break;
  81.         }
  82.       /* Fall through.  */
  83.     case '_':
  84.     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  85.     case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
  86.     case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
  87.     case 's': case 't': case 'u': case 'v': case 'w': case 'x':
  88.     case 'y': case 'z':
  89.     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  90.     case 'G': case 'H': case 'I': case 'J': case 'K':
  91.     case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
  92.     case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
  93.     case 'Y': case 'Z':
  94.       result->type = CPP_NAME;
  95.       {
  96.         struct normalize_state nst = INITIAL_NORMALIZE_STATE;
  97.         result->val.node = lex_identifier (pfile, buffer->cur - 1, false,
  98.                                            &nst);
  99.         warn_about_normalization (pfile, result, &nst);
  100.       }
  101.       /* Convert named operators to their proper types.  */
  102.       if (result->val.node->flags & NODE_OPERATOR)
  103.         {
  104.           result->flags |= NAMED_OP;
  105.           result->type = (enum cpp_ttype) result->val.node->directive_index;
  106.         }
  107.       break;
  108.     case '\'':
  109.     case '"':
  110.       lex_string (pfile, result, buffer->cur - 1);
  111.       break;
  112.     case '/':
  113.       /* A potential block or line comment.  */
  114.       comment_start = buffer->cur;
  115.       c = *buffer->cur;
  116.       
  117.       if (c == '*')
  118.         {
  119.           if (_cpp_skip_block_comment (pfile))
  120.             cpp_error (pfile, CPP_DL_ERROR, "unterminated comment");
  121.         }
  122.       else if (c == '/' && (CPP_OPTION (pfile, cplusplus_comments)
  123.                             || cpp_in_system_header (pfile)))
  124.         {
  125.           /* Warn about comments only if pedantically GNUC89, and not
  126.              in system headers.  */
  127.           if (CPP_OPTION (pfile, lang) == CLK_GNUC89 && CPP_PEDANTIC (pfile)
  128.               && ! buffer->warned_cplusplus_comments)
  129.             {
  130.               cpp_error (pfile, CPP_DL_PEDWARN,
  131.                          "C++ style comments are not allowed in ISO C90");
  132.               cpp_error (pfile, CPP_DL_PEDWARN,
  133.                          "(this will be reported only once per input file)");
  134.               buffer->warned_cplusplus_comments = 1;
  135.             }
  136.           if (skip_line_comment (pfile) && CPP_OPTION (pfile, warn_comments))
  137.             cpp_error (pfile, CPP_DL_WARNING, "multi-line comment");
  138.         }
  139.       else if (c == '=')
  140.         {
  141.           buffer->cur++;
  142.           result->type = CPP_DIV_EQ;
  143.           break;
  144.         }
  145.       else
  146.         {
  147.           result->type = CPP_DIV;
  148.           break;
  149.         }
  150.       if (!pfile->state.save_comments)
  151.         {
  152.           result->flags |= PREV_WHITE;
  153.           goto update_tokens_line;
  154.         }
  155.       /* Save the comment as a token in its own right.  */
  156.       save_comment (pfile, result, comment_start, c);
  157.       break;
  158.     case '<':
  159.       if (pfile->state.angled_headers)
  160.         {
  161.           lex_string (pfile, result, buffer->cur - 1);
  162.           break;
  163.         }
  164.       result->type = CPP_LESS;
  165.       if (*buffer->cur == '=')
  166.         buffer->cur++, result->type = CPP_LESS_EQ;
  167.       else if (*buffer->cur == '<')
  168.         {
  169.           buffer->cur++;
  170.           IF_NEXT_IS ('=', CPP_LSHIFT_EQ, CPP_LSHIFT);
  171.         }
  172.       else if (CPP_OPTION (pfile, digraphs))
  173.         {
  174.           if (*buffer->cur == ':')
  175.             {
  176.               buffer->cur++;
  177.               result->flags |= DIGRAPH;
  178.               result->type = CPP_OPEN_SQUARE;
  179.             }
  180.           else if (*buffer->cur == '%')
  181.             {
  182.               buffer->cur++;
  183.               result->flags |= DIGRAPH;
  184.               result->type = CPP_OPEN_BRACE;
  185.             }
  186.         }
  187.       break;
  188.     case '>':
  189.       result->type = CPP_GREATER;
  190.       if (*buffer->cur == '=')
  191.         buffer->cur++, result->type = CPP_GREATER_EQ;
  192.       else if (*buffer->cur == '>')
  193.         {
  194.           buffer->cur++;
  195.           IF_NEXT_IS ('=', CPP_RSHIFT_EQ, CPP_RSHIFT);
  196.         }
  197.       break;
  198.     case '%':
  199.       result->type = CPP_MOD;
  200.       if (*buffer->cur == '=')
  201.         buffer->cur++, result->type = CPP_MOD_EQ;
  202.       else if (CPP_OPTION (pfile, digraphs))
  203.         {
  204.           if (*buffer->cur == ':')
  205.             {
  206.               buffer->cur++;
  207.               result->flags |= DIGRAPH;
  208.               result->type = CPP_HASH;
  209.               if (*buffer->cur == '%' && buffer->cur[1] == ':')
  210.                 buffer->cur += 2, result->type = CPP_PASTE;
  211.             }
  212.           else if (*buffer->cur == '>')
  213.             {
  214.               buffer->cur++;
  215.               result->flags |= DIGRAPH;
  216.               result->type = CPP_CLOSE_BRACE;
  217.             }
  218.         }
  219.       break;
  220.     case '.':
  221.       result->type = CPP_DOT;
  222.       if (ISDIGIT (*buffer->cur))
  223.         {
  224.           struct normalize_state nst = INITIAL_NORMALIZE_STATE;
  225.           result->type = CPP_NUMBER;
  226.           lex_number (pfile, &result->val.str, &nst);
  227.           warn_about_normalization (pfile, result, &nst);
  228.         }
  229.       else if (*buffer->cur == '.' && buffer->cur[1] == '.')
  230.         buffer->cur += 2, result->type = CPP_ELLIPSIS;
  231.       else if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus))
  232.         buffer->cur++, result->type = CPP_DOT_STAR;
  233.       break;
  234.     case '+':
  235.       result->type = CPP_PLUS;
  236.       if (*buffer->cur == '+')
  237.         buffer->cur++, result->type = CPP_PLUS_PLUS;
  238.       else if (*buffer->cur == '=')
  239.         buffer->cur++, result->type = CPP_PLUS_EQ;
  240.       break;
  241.     case '-':
  242.       result->type = CPP_MINUS;
  243.       if (*buffer->cur == '>')
  244.         {
  245.           buffer->cur++;
  246.           result->type = CPP_DEREF;
  247.           if (*buffer->cur == '*' && CPP_OPTION (pfile, cplusplus))
  248.             buffer->cur++, result->type = CPP_DEREF_STAR;
  249.         }
  250.       else if (*buffer->cur == '-')
  251.         buffer->cur++, result->type = CPP_MINUS_MINUS;
  252.       else if (*buffer->cur == '=')
  253.         buffer->cur++, result->type = CPP_MINUS_EQ;
  254.       break;
  255.     case '&':
  256.       result->type = CPP_AND;
  257.       if (*buffer->cur == '&')
  258.         buffer->cur++, result->type = CPP_AND_AND;
  259.       else if (*buffer->cur == '=')
  260.         buffer->cur++, result->type = CPP_AND_EQ;
  261.       break;
  262.     case '|':
  263.       result->type = CPP_OR;
  264.       if (*buffer->cur == '|')
  265.         buffer->cur++, result->type = CPP_OR_OR;
  266.       else if (*buffer->cur == '=')
  267.         buffer->cur++, result->type = CPP_OR_EQ;
  268.       break;
  269.     case ':':
  270.       result->type = CPP_COLON;
  271.       if (*buffer->cur == ':' && CPP_OPTION (pfile, cplusplus))
  272.         buffer->cur++, result->type = CPP_SCOPE;
  273.       else if (*buffer->cur == '>' && CPP_OPTION (pfile, digraphs))
  274.         {
  275.           buffer->cur++;
  276.           result->flags |= DIGRAPH;
  277.           result->type = CPP_CLOSE_SQUARE;
  278.         }
  279.       break;
  280.     case '*': IF_NEXT_IS ('=', CPP_MULT_EQ, CPP_MULT); break;
  281.     case '=': IF_NEXT_IS ('=', CPP_EQ_EQ, CPP_EQ); break;
  282.     case '!': IF_NEXT_IS ('=', CPP_NOT_EQ, CPP_NOT); break;
  283.     case '^': IF_NEXT_IS ('=', CPP_XOR_EQ, CPP_XOR); break;
  284.     case '#': IF_NEXT_IS ('#', CPP_PASTE, CPP_HASH); break;
  285.     case '?': result->type = CPP_QUERY; break;
  286.     case '~': result->type = CPP_COMPL; break;
  287.     case ',': result->type = CPP_COMMA; break;
  288.     case '(': result->type = CPP_OPEN_PAREN; break;
  289.     case ')': result->type = CPP_CLOSE_PAREN; break;
  290.     case '[': result->type = CPP_OPEN_SQUARE; break;
  291.     case ']': result->type = CPP_CLOSE_SQUARE; break;
  292.     case '{': result->type = CPP_OPEN_BRACE; break;
  293.     case '}': result->type = CPP_CLOSE_BRACE; break;
  294.     case ';': result->type = CPP_SEMICOLON; break;
  295.       /* @ is a punctuator in Objective-C.  */
  296.     case '@': result->type = CPP_ATSIGN; break;
  297.     case '$':
  298.     case '\\':
  299.       {
  300.         const uchar *base = --buffer->cur;
  301.         struct normalize_state nst = INITIAL_NORMALIZE_STATE;
  302.         if (forms_identifier_p (pfile, true, &nst))
  303.           {
  304.             result->type = CPP_NAME;
  305.             result->val.node = lex_identifier (pfile, base, true, &nst);
  306.             warn_about_normalization (pfile, result, &nst);
  307.             break;
  308.           }
  309.         buffer->cur++;
  310.       }
  311.     default:
  312.       create_literal (pfile, result, buffer->cur - 1, 1, CPP_OTHER);
  313.       break;
  314.     }
  315.   return result;
  316. }

复制代码

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

鱼窥荷 2022-09-25 17:48:15

gcc 里的c和c++最早的时候都是用lex/yacc。后来先是c++改成了手工写的recursive descent语法分析器,然后c也改成手工写的了。

韵柒 2022-09-25 17:48:15

语法,词法分析比较简单,技术都成熟了,怎么写都行。

稳稳的幸福 2022-09-25 17:48:15

查了一下,v4.3.0的语法分析果然是用手工编写的(gcc/c-parser.c中 c_parse_file,8千行代码,还有一个gcc/cp/parser.c,2万行代码),巨汗!继续往前查,发现所能找到的最早版本v1.21(ftp://gcc.gnu.org/pub/gcc/old-releases/gcc-1/)的词法分析仍然是手工编写的,而语法分析是bison生成的。

樱桃奶球 2022-09-25 17:48:15

原帖由 emmoblin 于 2009-5-17 00:31 发表
语法,词法分析比较简单,技术都成熟了,怎么写都行。

说的是.

喵星人汪星人 2022-09-25 17:48:15

那么请问,如何手工编写语法分析程序呢?

例如
S->aAcBe
A->b
A->Ab
B->d

南城追梦 2022-09-25 17:48:15

原帖由 qtdszws 于 2009-5-20 09:00 发表
那么请问,如何手工编写语法分析程序呢?

例如
S->aAcBe
A->b
A->Ab
B->d

简单点纯手工编码的多数是针对LL的递归下降,大概做法就是先手工或者自动化的消除文法左递归和左因子,求first follow集合,针对LR的也存在一种叫低递归上升的编码方式,不过我不会也没见过这个,你可以搜一下。
递归下降比较好懂的例子就是计算器(里面有我刚学这类东西的时候扯的淡,这些淡你最好过滤掉它们,我当时也是一脑子浆糊)。

PS:这类东西都是成套路的,入门的话最好还是先学点简单的图算法,最起码龙书上那点自动机相关的(LL,SLR,LR,LALR)parser算法往图搜索上一套基本上就出来了,区别不过是构造顶点和边的方式不同(我个人认为纯手工的递归下降或者表驱动都属于对生成的图的用法不同,彻底弄明白一个也就都明白了)。

[ 本帖最后由 Solidus 于 2009-5-21 05:08 编辑 ]

吹泡泡o 2022-09-25 17:48:15

撑啊~好贴子~

心房敞 2022-09-25 17:48:15

原帖由 qtdszws 于 2009-5-20 09:00 发表
那么请问,如何手工编写语法分析程序呢?

例如
S->aAcBe
A->b
A->Ab
B->d

首先要对语法做变换,消除A->Ab中的左递归,变换后的语法是
S->aAcBe
A->bA | epsilon
B->d

这是一个LL(1) grammar, 龙书第二版第四章算法4.31就是LL(1) parsing table的构造算法,算法4.34是表驱动的predictive parsing算法

[ 本帖最后由 gta 于 2009-5-25 22:19 编辑 ]

神仙妹妹 2022-09-25 17:48:15

將 A- >b| Ab 改成
A->bA | epsilon
是有問題的
如此會產生'acde'這個string, 而此string
不屬於原本的grammar
left recursive 的改寫公式如下
A -> Aa|b
改寫成
A -> bR
R -> aR | epsilon

故於原始grammar裡,
A->b|Ab
可修改成
A->bR
R->bR | epsilon

LL(1) parser的建構方式很簡單,以
S->aAcBe為例:

S()
{
   if(lookahead() == 'a')
      match('a);
   else
      throw error;
   
   A();

   if(lookahead() == 'c')
     match('c');
   else
     throw error;

   B();

   if(lookahead() == 'e')
     match('e');
   else
     throw error;
}

其中 lookahead 會取出下一個token, match 會比較並消耗一個token

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文