C预编译实现

[废话]
    其实写C语言的解释器也是出于偶然的原因,本来只是想给自己的编辑器添加脚本解析的功能,或者简单的宏调用的功能。结果就想实现简单的C语言的脚本解析,后来干脆就想支持C的全部语法。至今还未完成...前几天实现了C的预编译的部分功能,主要是#define预编译宏。

    可以下载使用,呵呵:)

[预编译]
1. C的预编译主要是由代码中的预编译行实现,以#开始的行是预处理命令行,#前后可出现空白符,一行中可以只有#, 称为空白行。命令行后面可以有注释,可以\换行
2. C的预编译命令有很多,包括:
   #define
   #ifdef
   #ifndef
   #if
   #elif
   define
   #endif
   #
   ##
   等等...
   现在我仅仅是实现了#define, 包括函数形式的宏调用。

3. #define 宏的特点:
   a.  定义式宏,#define后面不是紧跟着(
       #define :
          "#define" name (sequence-of-tokens)?
          
   b.   函数式好宏,#define后紧跟(
        参数不能重名,宏体重可以不用提及所有的参数
        调用  1) ( 前可以有空格
              2) 参数以 ","来分隔参数列表,但是:macro( fun1(a,b), fun2() );
              中的fun1的参数列表不影响参数的解析!!
                 3) 宏中不会对自己的宏名做进一步扩展: marco( marco(a), b );
              这样子,宏名可以以函数名重复。
        #define :
          "#define" name"(" (identifier-list)? ")"

[实现方法]
1.  创建一个栈,用于记录所有的预编译行,暂时仅仅记录#define行。
2.  从头扫描脚本文件,查找符合的预编译行,将其入栈,并作处理。例如:
    脚本: #define  MARCO(a,b) ((a)+(b))
    那么,查找到该行时,必须按照下面的步骤处理:
    1) 得到#define 后面的宏名字 MARCO
    2) 判断MARCO后面是否紧跟着 ( 左括号。如果紧跟着,说明是函数式的宏调用,必须做进一步的解析,否则只要将后面的字符序列保存到栈中即可。
    3) 函数式宏的解析问题。 必须找到调用的参树,即上述例子中的a、b,并将其也保存到栈中。然后再将后面的序列((a)+(b))也保存下来。
3.  宏扩展问题,当扫描文件是,如果得到的字符是一个标识名,那么我们必须判断它是否被定义成宏。如果是,我们必须对它进行宏扩展。例如,我们现在扫描到一个串文本: MARCO( fun(a,b), b );
    那么我们搜索栈,知道MARCO被定义成函数式的宏,参数列表是a、b。所以继续往后解析,得到fun(a,b)和b, 替换掉((a)+(b))中的a和b,得到:((fun(a,b))+(b))。
    这时,其实事情还没结束,我们必须对((fun(a,b))+(b))做进一步的宏替换,如果fun又是被定义的一个宏,那么我们继续替换它,直至重复检查,没有可以替换的宏。
   
[举例]
#define  MAX  120
#define  MARCO(a,b) ((a)+(b))

MARCO( MAX, MARCO(a,b) );

1. 栈的内容:
宏名     参数个数      参数列表    字串序列
MAX      0                        120
MARCO    2            a b         ((a)+(b))

2. 宏调用MARCO( MAX, MARCO(a,b) );的展开过程:
   第一步:  ((MAX)+(MARCO(a,b)));
   第二步:  ((120)+(MARCO(a,b)));
   第三步:  继续替换,发现MARCO和自己同名,不会继续替换,不然将导致死循环。而且,这样子,宏名可以以函数名重复。
  
   最终结果:((120)+(MARCO(a,b)));

posted @ 2011-03-23 16:09  linxr  阅读(5963)  评论(2编辑  收藏  举报