免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 8353 | 回复: 13
打印 上一主题 下一主题

gcc中C语言的词法分析是怎么做的? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-16 10:16 |只看该作者 |倒序浏览
版本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. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2009-05-16 18:19 |只看该作者

回复 #1 qtdszws 的帖子

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

论坛徽章:
0
3 [报告]
发表于 2009-05-17 00:31 |只看该作者
语法,词法分析比较简单,技术都成熟了,怎么写都行。

论坛徽章:
0
4 [报告]
发表于 2009-05-17 22:45 |只看该作者
查了一下,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生成的。

论坛徽章:
0
5 [报告]
发表于 2009-05-19 21:15 |只看该作者
原帖由 emmoblin 于 2009-5-17 00:31 发表
语法,词法分析比较简单,技术都成熟了,怎么写都行。


说的是.

论坛徽章:
0
6 [报告]
发表于 2009-05-20 09:00 |只看该作者
那么请问,如何手工编写语法分析程序呢?

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

论坛徽章:
0
7 [报告]
发表于 2009-05-21 05:05 |只看该作者
原帖由 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 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2009-05-25 09:57 |只看该作者
撑啊~好贴子~

论坛徽章:
0
9 [报告]
发表于 2009-05-25 22: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 编辑 ]

论坛徽章:
0
10 [报告]
发表于 2009-05-27 11:44 |只看该作者

回复 #9 gta 的帖子

將 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
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP