现在的位置: 首页 > 综合 > 正文

LCC编译器的源程序分析(6)词法分析

2013年07月12日 ⁄ 综合 ⁄ 共 3282字 ⁄ 字号 评论关闭
在最开始的例子程序里,程序是由一些单词和符号组成的。其实程序就是一串长长的字符串,这些字符串是按一定的规则编写的,那么就需要检查这些单词和符号是否符合定义的规则。在C语言里,就是定义了C语法和语义。在最开始的例子里,C编译器最先进行词法分析的语句是下面这句:
typedef unsigned int size_t;
那么C编译器是怎么样把上面的字符串识别出来的呢?其实词法分析就是把上面的字符串识别为下面的单词:
typedef
unsigned
int
size_t
;
为了简单和比较方便,词法分析里会把这些单词用一个数字进行标识的,这样就容易存储和分析了。目标已经很明确,现在就来分析一下LCC的词法分析代码。
#001 init(argc, argv);
#002  
#003 t = gettok();
#004 
#005 (*IR->progbeg)(argc, argv);
 
在初始化函数init后面,就调用了词法分析函数gettok获取第一个记号。它的代码如下:
#001 int gettok(void)
#002 {
#003  for (;;)
#004  {
#005         register unsigned char *rcp = cp;
#006         while (map[*rcp]&BLANK)
#007               rcp++;
#008 
#009         if (limit - rcp < MAXTOKEN)
#010         {
#011               cp = rcp;
#012               fillbuf();
#013               rcp = cp;
#014         }
#015 
#016         src.file = file;
#017         src.x = (char *)rcp - line;
#018         src.y = lineno;
#019         cp = rcp + 1;
#020         switch (*rcp++)
#021         {
#022         case '/':
#023               if (*rcp == '*')
#024               {
#025                    int c = 0;
#026                    for (rcp++; *rcp != '/' || c != '*'; )
#027                         if (map[*rcp]&NEWLINE) {
#028                               if (rcp < limit)
#029                                      c = *rcp;
#030                               cp = rcp + 1;
#031                               nextline();
#032                               rcp = cp;
#033                               if (rcp == limit)
#034                                     break;
#035                         } else
#036                                c = *rcp++;
#037                    if (rcp < limit)
#038                         rcp++;
#039                    else
#040                         error("unclosed comment/n");
#041                    cp = rcp;
#042                    continue;
#043                 }
#044                 return '/';
#045         case '<':
#046               if (*rcp == '=') return cp++, LEQ;
#047               if (*rcp == '<') return cp++, LSHIFT;
#048               return '<';
#049         case '>':
#050               if (*rcp == '=') return cp++, GEQ;
#051               if (*rcp == '>') return cp++, RSHIFT;
#052               return '>';
#053         case '-':
#054               if (*rcp == '>') return cp++, DEREF;
#055               if (*rcp == '-') return cp++, DECR;
#056               return '-';
#057         case '=': return *rcp == '=' ? cp++, EQL    : '=';
#058         case '!': return *rcp == '=' ? cp++, NEQ    : '!';
#059         case '|': return *rcp == '|' ? cp++, OROR   : '|';
#060         case '&': return *rcp == '&' ? cp++, ANDAND : '&';
#061         case '+': return *rcp == '+' ? cp++, INCR   : '+';
#062         case ';': case ',': case ':':
#063         case '*': case '~': case '%': case '^': case '?':
#064         case '[': case ']': case '{': case '}': case '(': case ')':
#065               return rcp[-1];
#066         case '/n': case '/v': case '/r': case '/f':
#067               nextline();
#068               if (cp == limit) {
#069                    tsym = NULL;
#070                    return EOI;
#071               }
#072               continue;
#073 
3行是一个没有条件for循环,就是想识别出一个记号才返回。
5行是获取当前输入缓冲区的指针。
6行、第7行是去掉空白字符。
9行到第14行是判断输入缓冲区小于最大的记号时,就重新从文件里获取源程序,填充到缓冲区里。
16行到第18行是记录前记号的开始位置,以便出错时可以定位出错的源程序位置。
19行是处理识别一个字符的移动指针,让它指向下一个字符。
20行开始,就是根据第一个字符来进行识别处理,它是使用一个switch来实的。
22行到第44行是识别了C程序的注释,并把这些注释删除。
45行到第48行是识别小于’<’,小于等于’<=’,左移’<<’
49行到第52行是识别大于,大于等于,右移。
53行到第56行是识别引用’->’,自减’--‘,减号’-‘
57行是识别等号或赋值。
58行是识别不等或非操作符。
59行是或和位或运行算符。
60行是与和位与运算符。
61行是自加和加号运算符。
62行到65行是分号、逗号等等单个符号识别。
66行到第72行是换行符识别,并获取下一行代码。
到这里就已经分析了很多符号的处理,后面主要是关键字、ID和常量的识别。

 

抱歉!评论已关闭.