VBGood网站全文搜索 Google

搜索VBGood全站网页(全文搜索)

VB爱好者乐园(VBGood)

 找回密码
 立即注册
搜索
查看: 8007|回复: 20

ANSI C 的 Lex 和 Yacc

[复制链接]
 楼主| 发表于 2010-8-25 00:46:59 | 显示全部楼层 |阅读模式
本帖最后由 VBProFan 于 2010-8-25 11:38 编辑

篇幅有限,只贴个 AnsiC.L 出来吧,因为我打算准备用 VB6 写一个 ANSI C 的词法分析器,贴出来有助于我查找它的词汇表。

  1. D   [0-9]
  2. L   [a-zA-Z_]
  3. H   [a-fA-F0-9]
  4. E   [Ee][+-]?{D}+
  5. P                       [Pp][+-]?{D}+
  6. FS   (f|F|l|L)
  7. IS                      ((u|U)|(u|U)?(l|L|ll|LL)|(l|L|ll|LL)(u|U))
  8. %{
  9. #include <stdio.h>
  10. #include "y.tab.h"
  11. void count(void);
  12. %}
  13. %%
  14. "/*"   { comment(); }
  15. "//"[^\n]*              { /* consume //-comment */ }

  16. "auto"   { count(); return(AUTO); }
  17. "_Bool"   { count(); return(BOOL); }
  18. "break"   { count(); return(BREAK); }
  19. "case"   { count(); return(CASE); }
  20. "char"   { count(); return(CHAR); }
  21. "_Complex"  { count(); return(COMPLEX); }
  22. "const"   { count(); return(CONST); }
  23. "continue"  { count(); return(CONTINUE); }
  24. "default"  { count(); return(DEFAULT); }
  25. "do"   { count(); return(DO); }
  26. "double"  { count(); return(DOUBLE); }
  27. "else"   { count(); return(ELSE); }
  28. "enum"   { count(); return(ENUM); }
  29. "extern"  { count(); return(EXTERN); }
  30. "float"   { count(); return(FLOAT); }
  31. "for"   { count(); return(FOR); }
  32. "goto"   { count(); return(GOTO); }
  33. "if"   { count(); return(IF); }
  34. "_Imaginary"  { count(); return(IMAGINARY); }
  35. "inline"  { count(); return(INLINE); }
  36. "int"   { count(); return(INT); }
  37. "long"   { count(); return(LONG); }
  38. "register"  { count(); return(REGISTER); }
  39. "restrict"  { count(); return(RESTRICT); }
  40. "return"  { count(); return(RETURN); }
  41. "short"   { count(); return(SHORT); }
  42. "signed"  { count(); return(SIGNED); }
  43. "sizeof"  { count(); return(SIZEOF); }
  44. "static"  { count(); return(STATIC); }
  45. "struct"  { count(); return(STRUCT); }
  46. "switch"  { count(); return(SWITCH); }
  47. "typedef"  { count(); return(TYPEDEF); }
  48. "union"   { count(); return(UNION); }
  49. "unsigned"  { count(); return(UNSIGNED); }
  50. "void"   { count(); return(VOID); }
  51. "volatile"  { count(); return(VOLATILE); }
  52. "while"   { count(); return(WHILE); }
  53. {L}({L}|{D})*  { count(); return(check_type()); }
  54. 0[xX]{H}+{IS}?  { count(); return(CONSTANT); }
  55. 0{D}+{IS}?  { count(); return(CONSTANT); }
  56. {D}+{IS}?  { count(); return(CONSTANT); }
  57. L?'(\\.|[^\\'\n])+' { count(); return(CONSTANT); }
  58. {D}+{E}{FS}?  { count(); return(CONSTANT); }
  59. {D}*"."{D}+({E})?{FS}? { count(); return(CONSTANT); }
  60. {D}+"."{D}*({E})?{FS}? { count(); return(CONSTANT); }
  61. 0[xX]{H}+{P}{FS}?               { count(); return(CONSTANT); }
  62. 0[xX]{H}*"."{H}+({P})?{FS}?     { count(); return(CONSTANT); }
  63. 0[xX]{H}+"."{H}*({P})?{FS}?     { count(); return(CONSTANT); }

  64. L?"(\\.|[^\"\n])*" { count(); return(STRING_LITERAL); }
  65. "..."   { count(); return(ELLIPSIS); }
  66. ">>="   { count(); return(RIGHT_ASSIGN); }
  67. "<<="   { count(); return(LEFT_ASSIGN); }
  68. "+="   { count(); return(ADD_ASSIGN); }
  69. "-="   { count(); return(SUB_ASSIGN); }
  70. "*="   { count(); return(MUL_ASSIGN); }
  71. "/="   { count(); return(DIV_ASSIGN); }
  72. "%="   { count(); return(MOD_ASSIGN); }
  73. "&="   { count(); return(AND_ASSIGN); }
  74. "^="   { count(); return(XOR_ASSIGN); }
  75. "|="   { count(); return(OR_ASSIGN); }
  76. ">>"   { count(); return(RIGHT_OP); }
  77. "<<"   { count(); return(LEFT_OP); }
  78. "++"   { count(); return(INC_OP); }
  79. "--"   { count(); return(DEC_OP); }
  80. "->"   { count(); return(PTR_OP); }
  81. "&&"   { count(); return(AND_OP); }
  82. "||"   { count(); return(OR_OP); }
  83. "<="   { count(); return(LE_OP); }
  84. ">="   { count(); return(GE_OP); }
  85. "=="   { count(); return(EQ_OP); }
  86. "!="   { count(); return(NE_OP); }
  87. ";"   { count(); return(';'); }
  88. ("{"|"<%")  { count(); return('{'); }
  89. ("}"|"%>")  { count(); return('}'); }
  90. ","   { count(); return(','); }
  91. ":"   { count(); return(':'); }
  92. "="   { count(); return('='); }
  93. "("   { count(); return('('); }
  94. ")"   { count(); return(')'); }
  95. ("["|"<:")  { count(); return('['); }
  96. ("]"|":>")  { count(); return(']'); }
  97. "."   { count(); return('.'); }
  98. "&"   { count(); return('&'); }
  99. "!"   { count(); return('!'); }
  100. "~"   { count(); return('~'); }
  101. "-"   { count(); return('-'); }
  102. "+"   { count(); return('+'); }
  103. "*"   { count(); return('*'); }
  104. "/"   { count(); return('/'); }
  105. "%"   { count(); return('%'); }
  106. "<"   { count(); return('<'); }
  107. ">"   { count(); return('>'); }
  108. "^"   { count(); return('^'); }
  109. "|"   { count(); return('|'); }
  110. "?"   { count(); return('?'); }
  111. [ \t\v\n\f]  { count(); }
  112. .   { /* Add code to complain about unmatched characters */ }
  113. %%
  114. int yywrap(void)
  115. {
  116. return 1;
  117. }

  118. void comment(void)
  119. {
  120. char c, prev = 0;
  121.   
  122. while ((c = input()) != 0)      /* (EOF maps to 0) */
  123. {
  124.   if (c == '/' && prev == '*')
  125.    return;
  126.   prev = c;
  127. }
  128. error("unterminated comment");
  129. }

  130. int column = 0;
  131. void count(void)
  132. {
  133. int i;
  134. for (i = 0; yytext != '\0'; i++)
  135.   if (yytext == '\n')
  136.    column = 0;
  137.   else if (yytext == '\t')
  138.    column += 8 - (column % 8);
  139.   else
  140.    column++;
  141. ECHO;
  142. }

  143. int check_type(void)
  144. {
  145. /*
  146. * pseudo code --- this is what it should check
  147. *
  148. * if (yytext == type_name)
  149. *  return TYPE_NAME;
  150. *
  151. * return IDENTIFIER;
  152. */
  153. /*
  154. * it actually will only return IDENTIFIER
  155. */
  156. return IDENTIFIER;
  157. }
复制代码
lex 和 yacc 的 Ansi C.rar (22.88 KB, 下载次数: 610)
 楼主| 发表于 2010-8-25 15:32:25 | 显示全部楼层
本帖最后由 VBProFan 于 2010-8-25 15:37 编辑

有个问题请教一下大家,像:
“#include<stdlib.h>”
这种情况怎么办?

1. 假如把“<”看做一个单独的词,那么 stdlib . h > 就是四个单独的词了,如果这个头文件名里面有特殊字符,如空格、句点、等号等等,那就明显不对了,文件名就应该是一个词而已,却被分开了;

2. 假如把“<”看做字符串起始符号,“>”看做字符串的终止符号,那么遇到 a + b < c 这种有大于号的情况时又不对了;

3. 根据前面是否有 include 来区分“<”是左尖括号还是小于号,但这好像又是语法分析,不属于词法分析的范畴了。

上面的 Lex 的程序似乎也没有考虑到这种情况。
回复 支持 反对

使用道具 举报

发表于 2010-8-25 20:39:28 | 显示全部楼层
呵呵,我原本打算用VB6实现山寨Lex和YACC……前一个基本实现了,后一个没实现……

至于你2楼的问题,预处理器把#开头的语句全部砍掉了……
回复 支持 反对

使用道具 举报

发表于 2010-8-25 20:53:49 | 显示全部楼层
#include<stdlib.h>
好像是把stdlib.h的内容直接插到这个位置,然后再处理
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-8-25 22:21:54 | 显示全部楼层
本帖最后由 VBProFan 于 2010-8-25 22:23 编辑
呵呵,我原本打算用VB6实现山寨Lex和YACC……前一个基本实现了,后一个没实现……

至于你2楼的问题,预处理器把#开头的语句全部砍掉了……
acme_pjz 发表于 2010-8-25 20:39


这么牛叉?Lex 做出来了?怎么不放出来让我们玩玩呢?
Yacc 做不出来可以做个容易一点的吧。像通过构造 First 和 Follow 集合得到 LL(1)分析器貌似还是比较简单的。
原来预处理器并非用词法和语法分析的技术(有限自动机和下推自动机),估计是用一些高级字符串处理函数,就像我以前搞的一些山寨的词法语法分析程序一样 (例如语法高亮的汇编开发环境、C Func 转 VB、VB Prolog 解释器……)
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-8-25 22:25:58 | 显示全部楼层
本帖最后由 VBProFan 于 2010-8-25 22:30 编辑
#include
好像是把stdlib.h的内容直接插到这个位置,然后再处理
download 发表于 2010-8-25 20:53


这个地球人都知道,不过我到现在还没想明白,如果出现语法错误(分h文件和c文件两种情况),要定位时就复杂了。如果你用h文件的字符串来替换到这里,在c中出现语法错误,你显示的只能是在c中的行数,但对 LR 分析器来说,它分析的是替换后的字符串……

难道在内存中保存两份字符串,一份是替换前的c的,一份是替换后的c的?
回复 支持 反对

使用道具 举报

发表于 2010-8-26 08:55:32 | 显示全部楼层
估计是先分析h,有错就报错,没错就合并到c
头文件出错VC好像是直接报h的行号。这种情况还是比较容易,
CPP的那个模板才复杂,调试也很可怕,幸好VC支持的比较好。
回复 支持 反对

使用道具 举报

发表于 2010-8-26 12:45:14 | 显示全部楼层
6# VBProFan

不是,只生成一个合并后的文件,不过里面可能有#file或#line等关键字,在词法分析程序读到的时候就更新文件名和行号信息……

评分

参与人数 1威望 +8 人气 +1 收起 理由
VBProFan + 8 + 1 原来如此,明白了

查看全部评分

回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-8-28 00:41:45 | 显示全部楼层
发现一个好东西:

http://blog.csdn.net/huyansoft/archive/2008/05/26/2484297.aspx
C/C++预处理 ISO/ANSI C标准译文与注解
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-8-29 08:55:30 | 显示全部楼层
在看语法分析的文法定义部分时,我就在想:C的文法应该如何定义呢?太复杂了,怎么想都想不出,回来再一看 Ansi C 的 Yacc 源码,恍然大悟,真是太经典了,忍不住发几条上来:


jump_statement
: GOTO IDENTIFIER ';'
| CONTINUE ';'
| BREAK ';'
| RETURN ';'
| RETURN expression ';'
;

这是对跳转语句的总结,表面上看上去很不同的 goto 和 return,居然是一起处理的,到现在还想不出为什么,汇编不是也有子程序和return语句吗?难道C的return也翻译为jnz之类的?。而continue和break一开始看上去时反应不过来,想想后确实也是翻译为jnz之类的。
external_declaration
: function_definition
| declaration
;

这个基本上接近开始符号了,C程序就是由全局声明和函数定义组成的。
iteration_statement
: WHILE '(' expression ')' statement
| DO statement WHILE '(' expression ')' ';'
| FOR '(' expression_statement expression_statement ')' statement
| FOR '(' expression_statement expression_statement expression ')' statement
| FOR '(' declaration expression_statement ')' statement
| FOR '(' declaration expression_statement expression ')' statement
;

对循环语句的总结,呵呵。
selection_statement
: IF '(' expression ')' statement
| IF '(' expression ')' statement ELSE statement
| SWITCH '(' expression ')' statement
;

对分支语句的总结,呵呵。
expression_statement
: ';'
| expression ';'
;

语句组可以是空语句,也可以是语句序列,最简单的左递归定义。
statement
: labeled_statement
| compound_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
;

这个也很经典,语句的类型。

几乎全是经典啊~ 我要翻译、整理、打印出来膜拜和诵读。整个 C 的语法仅400多行就可以全部精确的描述,真是太神奇了!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

文字版|手机版|小黑屋|VBGood  

GMT+8, 2023-3-22 04:57

VB爱好者乐园(VBGood)
快速回复 返回顶部 返回列表