语法文件解释器及编译器代码生成

1 文法文件的定义

语法文件使用的是LL分析方法。LL分析最简便的就是使用递归程序,或构造自动机。 WACC中,采取的硬编码的方式构造自动机。所谓硬编码,是与上章讲的按表格驱动实现自动机相对的。表格驱动往往采用一种二维数组(有可能是一种压缩的)构成状态转换表。程序读取当前符号和当前状态,查询表格来决定下个状态。代码相对比较短,对于不同的问题,仅仅需要修改表格的内容,而不需要修改代码就能解决。硬编码方式就是直接采用代码实现自动机,如果自动机不同,实现代码也会不同。

利用状态变量和case语句便可实现DFA。

给定一个识别标志符自动机如下:

图表 51

  伪代码如下:

state = 1

while state ==1 ,2 

BeginWhile

  switch(state)

  BeginSwitch

   case 1:

   if get character is letter then

   state = 2

   Else 

   report it has error

   case 2:

   if get character is letter or digit then

   state = 2

   Else

   report accept and return

  EndSwitch

EndWhile

语法文件的定义很简单,在前言中就讲过:

语法定义:

非终结符 -> 产生式{规约动作};

产生式由0个或多个symbol(符号)组成。在上面的定义的基础上,我们稍作修改,成为下面的一个文法了:

LEFT ARROW RIGHT 

其中,LeftArrow是必须的,Right可空。LEFTRight定义如下:

LEFT:name

ARROW:conductor

RIGHT:{name}{block}

其中,conductor指箭头,block指规约动作。

绘制出DFA状态图

图表 52

可以看到,该DFA十分简单,这也就是为什么使用硬编码来实现语法文件的解释的原因。Block0-1)表示Block可以出现0-1次,Name0-+)表示Name可以出现0次到多次。

1.1 CInterpreter类

CInterpreter类可以说是用户与系统的一个交互类。用户定义语法文件,便是系统的输入。通过CInterpreter解释语法文件,同时,CInterpreter也根据语法文件生成的LALR1)分析表生成分析程序。

CIneterpreter类如下定义:

class CInterpreter  

{

public:

void InterBlock();

void FormCase(CLanguage &L,FILE* f);

    CInterpreter();

    virtual ~CInterpreter();

    TokenType getToken(CLanguage &L);

    std::string string_value;

    //取得rules 

    void getRules(CLanguage &L);

    string action_string;

    int StartOfReduce ;

    /* -1 为 出错,0 ~ StartOfReduce -1   表示shift 或 goto

    StartOfReduce ~ruduce 

    */

    vector<std::string> ActionVec;

    std::map<std::string,int> strMap;

void FormAnsyTable(CIset& Iset, CLanguage &L);

private:

void getDefine(CLanguage &L);

    static int value;

    void createNewSym(CLanguage &L,string &strValue);

    void initLine(vector<int> &line);

    // fetch index of symbol input ,if error return -1,else return the index  

    int  fetchIndSym(CSymbol *sy,CLanguage &L);

    void error();

    void createNewRul(CLanguage &L, RULTYPE & aRule);

    inline void checkReduce( CLanguage &L,vector<int> &line,CItem &Item );

};

与解释器有关的几个函数有getToken和getRules函数,其中getTokengetRules函数调用的。FormAnsyTable函数是用来生成分析程序的。string_value变量用来记录每次getToken操作所取得的字符串值。而strMap变量是一个符号表。文法每次定义出来的变量,均交由strMap存储,并且由strMap定义索引值。这些变量名称和索引值可以生成文法所需的Symbol

1.2 getRules函数

函数getRules并不长,基本是按图表 52所示的自动机的实现的,实现方式也就是swich case的代码。与上面提到的伪代码使用相同的模式,没有太多的技巧。它调用的getToken函数同样采用编码实现自动机,同样没有采用太多的技巧。

void CInterpreter::getRules(CLanguage &L)

{

    enum STATE 

    { LEFT, ARROW,RIGHT,ACTION} state = LEFT;

    TokenType ty;

    vector<RULTYPE> RuleSet;

    //以下进行反复

    RULTYPE aRule;

    aRule.rightpart.clear();

    getDefine(L);

    while ( END != (ty = getToken(L)))

    { 

        switch( state )

        {

            case LEFT: 

                //match name, NOT match return error 

                if ( ty != NAME &&

                    ty != PRINT)

                {

                    cout<<"LEFT"<<endl;

                    error();

                    return ;

                }

    

                break;

            case ARROW:

                //match conductor, NOT match return error

                if ( ty != CONDUCTOR )

                {

                    cout<<"CONDUCTOR"<<endl;

                    error();

                    return ;

                }

                state = RIGHT;

                break;

            case RIGHT:

                //match name, NOT match return error    

                 if ( ty != NAME && ty != PRINT && ty !=BLOCK )

                {

                    cout<<"RIGHT"<<endl;

                    error();

                    return ;

                }

                if ( ty == NAME )

                {

                    //get RightPart

                    aRule.rightpart.push_back(strMap[string_value]);

                    state = RIGHT;

                }

                else if ( ty == BLOCK || ty == PRINT)

                {

                    if ( ty == BLOCK )

                    {

                        //将action  表插入式中

                        this->ActionVec.push_back(this->action_string);

                        if ( PRINT ==

                            ( ty = getToken( L) )  )

                        {

                            RuleSet.push_back(aRule);

                            aRule.rightpart.clear();

                        }

                        else 

                        {

                            cout<<"ty is:"<<ty<<endl;

                            cout<<"BLOCK"<<endl;

                            error();

                        }

                    }

                    else if ( ty == PRINT )

                    {

                        //在ActionVec 填入空action_string 

                        ActionVec.push_back("");

                        RuleSet.push_back(aRule);

                        aRule.rightpart.clear();

                    }

                    //set state to LEFT

                    state = LEFT;

                }  

                break;

            default:

                    cout<<"default"<<endl;

                error();

                break;

        }

    }

    //根据ruleset 产生Language 的rules

    for ( int i = 0 ; i < RuleSet.size(); i++ )

    {

       //取出aRule 产生rules插入L 

       createNewRul(L,RuleSet[i]);

    }

}

1.3 FormAnsyTable函数

FormAnsyTable函数更简单,它采用fprintf函数向文件写代码。这里不再赘述,请看附录II所列出的源代码。

本章的测试代码有Test9Test10Test11

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值