loop_in_codes

低调做技术__欢迎移步我的独立博客 codemaro.com 微博 kevinlynx

实现一种解释性脚本语言(三)

author: Kevin Lynx email: zmhn320#163.com date: 3.7.2009

词法分析

    词法分析属于整个编译流程中的第一个阶段。为什么要把编译过程分为多个阶段,这就
如同软件分层一样,个人觉得是出于降低复杂性的考虑。
    再次声明我不会告诉你任何编译原理的理论知识,因为坦率地说我也不会:D。所以我努
力将我们需要了解的概念尽可能简单地告诉你。当然,可能会与教科书不吻合。

什么是词法分析?

    词法分析就是把一段话整理成单词集合。举个简单的例子,例如有代码:age = age + 1;,
经过词法分析后,将得到:age、=、age、+、1、;几个符号。为了方便,我称每个单词为一
个token。

词法分析的作用

    词法分析分析出来的单词集合,直接作为编译流程中接下来的语法分析的输入。那么语
法分析阶段面对的将是一个一个的token,而不是单个的字符。
    例如,在处理age = age + 1;这种语句时,当我们获取到token "="时,我们直接期望接
下来的token应该是个表达式。以单词为单位地处理,比直接处理单个字符简单很多。

词法分析的过程

    词法分析的输入是单个字符流,一般我们fopen一个源代码文件,保存在一个char缓存
里,这就是词法分析的输入。而词法分析的最终输出结果就是一个一个的token。
    为了处理方便,token并不是单纯的单词。通常我们会将源代码中的所有单词分类,例
如变量名其实都属于一类token。简单的token可定义为:
    struct Token
    {
        int type;
        char value[256];
    };
    type用于表示token的类型,例如一个变量名token的类型是一个标识符。value可以用
来具体地保存这个变量的名字。

    对于type的处理,通常会事先定义一组枚举值,例如:
    enum    {    ID, NUM, STRING, IF, ELSE, WHILE, RETURN, FUNCTION }等等用于标示
在一个源代码中可能出现的所有token。

    虽然说词法分析的结果是一个token集合,但事实上我们并不是一次做完词法分析。通常
词法分析模块提供一个get_token函数。每次调用该函数时,都返回源代码中下一个token。
例如,有源代码:age = age + 1;
    第一次调用get_token将获得 { ID, "age" },第二次获得 { ASSIGN, "=" },第三次
获得{ ID, "age" },等等。

    那么,词法分析该如何实现?也就是struct Token get_token()函数如何实现?其实很
简单,你告诉我:给你一个字符串,你如何判断这个字符串全部是数字?
    int is_num( const char *str )
    {
        while( *str != 0 )
        {
            if( !isdigit( *str++ ) ) return 0;
        }
        return 1;
    }
    所以,基本上,词法分析的过程也就是这个过程。就拿标识符举例,典型的标识符一般
以字符开头,然后接着是数字或字符或_,当遇到非法字符时,这个标识符的扫描即结束。
    词法分析一般是个while+switch:
    struct Token get_token()
    {
        while( current_char != 0 )
        {
            switch( current_char )
            {
                case CHARACTER:
                    /* 扫描一个标识符 token */
                    break;

                case '=':
                    /* 获得一个 ASSIGN token */
                    break;

                    ...
            }
        }
    }

    现在,试着去总结一门语言里的每一个token的规则,然后自己去写写看。

代码导读

    在本节我将提供kl在googlecode的SVN上的代码,先不要去管代码包中的其他东西。关于
词法的代码可以在kllex.c kllex.h中找到。lex_token是提供给其他模块的接口,用于获取
当前扫描的token。扫描结果可以通过lexState结构体获取。
    再次提下版权问题,代码文件以及代码包中我并没有加入任何版权说明,哪怕是GPL。
但是如同我之前说的一样,我不介意你传播、改动此代码,但是请保留原作者信息。当然,
我并不介意你加上@modified by xxx:)。

    下载kl源代码:http://klcommon.googlecode.com/files/kllan_0.1.0.zip

posted on 2009-03-07 13:43 Kevin Lynx 阅读(3775) 评论(2)  编辑 收藏 引用 所属分类: kl脚本实现编译原理

评论

# re: 实现一种解释性脚本语言(三) 2009-03-15 16:28 梦在天涯

while( *str != 0 )
{
if( !isdigit( *str ) ) return 0;
}

为什么不是if(str != 0)
{
if(!isdigit(*str) return 0;
}
return 1;  回复  更多评论   

# re: 实现一种解释性脚本语言(三) 2009-03-15 16:47 Kevin Lynx

@梦在天涯
这个例子是用于判定一个字符串是否全部是数字,不过例子中写的有问题,应该是:
int is_number( const char *str )
{
while( *str != 0 )
{
if( !isdigit( *str++ ) ) return 0;
}
return 1;
}

谢谢提醒。
  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理