[转载]LCC编译器的源程序分析(6)词法分析

在最开始的例子程序里,程序是由一些单词和符号组成的。其实程序就是一串长长的字符串,这些字符串是按一定的规则编写的,那么就需要检查这些单词和符号是否符合定义的规则。在 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 和常量的识别。
 

你可能感兴趣的:([转载]LCC编译器的源程序分析(6)词法分析)