⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lex.cpp

📁 编译原理中的First集与 Follow集生成程序
💻 CPP
字号:
/*
 *	file:  lex.cpp
 *  func:  The lexical parser program file.
 */

#include <iostream>
#include <exception>
#include <fstream>
#include <string>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include "lex.h"
using std::string;
using std::exception;
using std::cout;

Lex::Lex(const string &fname):pfname(fname)
{
    lineno=1;
    nerror=0;
    ungetflag=False;

    /// 打开待分析的源文件.
    pf.open(fname.c_str());
    if(!pf)
    {
        cout<<"打开文法文件 "<< fname <<" 错误.\n";
        exit(1);
    }
}


Void
Lex::showErr(errortype who)
{
    ++nerror;
    switch(who)
    {
    case UNKNOWN:
        cout<<'('<<lineno<<')'<<"未知错误.\n";break;
    case UNTERMINATED_COMMENT:
        cout<<'('<<lineno<<')'<<"注释缺少(*/)结束符.\n";break;
    case UNTERMINATED_STRING:
        cout<<'('<<lineno<<')'<<"字符串尾缺少(\").\n";break;
    case OUT_OF_RANGE:
        cout<<'('<<lineno<<')'<<"标识符的长度大于"<<MAXTOKENLEN-1<<".\n";break;
    case MUST_KEYWORD:
        cout<<'('<<lineno<<')'<<"缺少关键字.\n";break;
    case LITERAL_ERROR:
        cout<<'('<<lineno<<')'<<"字符常量错误.\n";break;
    case ESCAPE_ERROR:
        cout<<'('<<lineno<<')'<<"错误的转义字符"<<errorstring<<".\n";break;
    case LACK_QUOTE:
        cout<<'('<<lineno<<')'<<"缺少引号.\n";break;
    case PERCENT_ERROR:
        cout<<'('<<lineno<<')'<<"\"%\"后的符号无效.\n";break;
    case UNKNOWN_LITERAL:
        cout<<'('<<lineno<<')'<<"不能识别的符号\""<<errorstring<<"\".\n";break;

    default:
        assert(0);
        break;
    }
}

/// 返回字符串中的最后一个符号(双引号,回车号,文件结束符).
sint32
Lex::eatup_string()
{
    //1 char * cc="lvjin\"";
    //2 char * cc="lvjin\\";
    //3 char * cc="lvjin\
    //  jinhua";
    //4 char * cc="lvjin
    //5 char *xx="lvjinhua""aaaa"\
    //    "ddd";
    //5 char *xx="lvjinhua""aaaa"
    //    "ddd";

    register sint32 c;
    register Bool instring=True;
    while(instring)
    {
        instring=True;
        c=pf.get();
        while(c!='\\' && c!='\"' && c!='\n' && ENDOFFILE!=c)
            c=pf.get();
        if('\\'==c)
        {
            c=pf.get();
            if('\n'==c)  // 续行.
                ++lineno;
            else if(ENDOFFILE==c)
            {
                instring=False;
            }
            // 
            // 如果不是第3种情况.即跳过'\x'后的一个字符,
            // 第3种情况是C语言的续行操作,行号加1.
        }
        else if('\"'==c)
            instring=False;
        else if('\n'==c)
        {
            showErr(UNTERMINATED_STRING);
            ++lineno;
            instring=False;
        }
        else if(ENDOFFILE==c)
        {
            instring=False;
        }
#ifdef _DEBUG
        else
        {
            assert(0);
        }
#endif //_DEBUG

    }// while(instring)
    return c;
}

/*
 *	去除Bison中的 "/* * /'及'//'注释.
 *  返回注释后的下一个字符.
 */
sint32 
Lex::eatup_white_comment()
{
    register sint32 c;
    for(;;)
    {
        c=pf.get();
        switch(c)
        {
        case '/':
        {
            c=pf.get();
            if('*'==c)
            {//处理C语言的 '/* */' 注释内容.
                register Bool incomment=True;
                while(incomment)
                {
                    while('*'!=(c=pf.get()) && '\n'!=c
                             && ENDOFFILE!=c)
                        /* empty */;

                    if('*'==c && '/'==pf.peek())
                    {
                        pf.get();
                        incomment=False;
                    }

                    else if('\n'==c)
                        ++lineno;

                    else if('*'==c && ('/'!=pf.peek()))
                        /* empty */;
                    else
                    {
                        showErr(UNTERMINATED_COMMENT);
                        return ENDOFFILE;
                    }

                }// while(incomment)
            }
            else if('/'==c)
            {// 处理C++的 '//' 注释内容.
                do{
                    c=pf.get();
                }while('\n'!=c && ENDOFFILE!=c);// && '\\' !=c);

                if('\n'==c)
                {
                    ++lineno;
                    return pf.get();
                }
                else 
                    return c;
            }
            else
            {// 并非注释的开始.
                pf.unget();
                return '/';
            }
            break;
        }
        case '\n':
            ++lineno;       // 行号加1.
            //c=pf.get();     // 读入下一个字符.
            break;
        case ' ':
        case '\t':
        case '\f':
            do{
                c=pf.get();
            }while(' '==c || '\t' ==c || '\f'==c);
            pf.unget();
            break;
        default:
            return c;
        }
    }// for(;;)
    //return c;
    showErr(UNKNOWN);
}


string
Lex::read_Identifier() // istream pf
{
    char str[MAXTOKENLEN]={'\0'};
    register uint32 size=0;
    register uchar8 c=pf.get();
    if(isalpha(c) || '_'==c || '.'==c)
    {
        do{
            str[size++]=c;
            c=pf.get();
            if(size >= MAXTOKENLEN)
            {
                showErr(OUT_OF_RANGE);
                while( isalnum(c) || c=='_' || '.'==c)
                    c=pf.get();
                break;
            }
        }while(isalnum(c) || '_'==c || '.'==c);
        pf.unget();
        if(size<MAXTOKENLEN)
            str[size]='\0';
        else
            str[MAXTOKENLEN-1]='\0';
        return string(str,str+size) ;
    }
    else
    {
        assert(0);
        pf.unget();
        return string("");
    }
}


sint32
Lex::lex()
{
    if (ungetflag)
    {
        ungetflag=False;
        strval=unstrval;
        numval=unnumval;
        return untoken;
    }

    register sint32 c;
again:
    strval.clear();
    c=eatup_white_comment();
    if(isalpha(c) || '_'==c || '.'==c)
    { // 标识包含以字母,下划线与点开头的以字母 数字 下划线 点组成的
      // 长度小于 MAXTOKENLEN 的序列。
        pf.putback(c);
        
        strval=read_Identifier();

        numval = -1;

        assert(strval.size()>0);
        return ID;
    }
    else if(isdigit(c))
    {
        uchar8 digitstr[MAXDIGITLEN];
        uint32 size=0;
        do{
            digitstr[size++]=c;
            c=pf.get();
            if(size>=MAXDIGITLEN)
            {
                showErr(OUT_OF_RANGE);
                while(isdigit(c))
                    c=pf.get();
                break;
            }
        }while(isdigit(c));
        pf.unget();

        digitstr[size]='\0';
        strval.assign(digitstr,digitstr+size);
        numval=atoi((char*)digitstr);

        return NUM;
    }
    else
    switch(c)
    {
    case '%':
        c=pf.get();
        if('%'==c){
            strval="%%";
            return MARK;
        }

        else if('{'==c){
            strval="%{";
            return LCURL;
        }

        else if('}'==c){
            strval="%}";
            return RCURL;
        }

        else if(isalpha(c)||'_'==c)
        {
            pf.unget();
            strval=read_Identifier();
            if("token"==strval)         return TOKEN;
            else if("left"==strval)     return LEFT;
            else if("right"==strval)    return RIGHT;
            else if("nonassoc"==strval) return NONASSOC;
            else if("prec"==strval)     return PREC;
            else if("type"==strval)     return TYPE;
            else if("start"==strval)    return START;
            else if("union"==strval)    return UNION;
#ifdef EXTEND
            else if("except"==strval)   return EXCEPT;
            else if("pure_parser"==strval)return PURE_PARSER;
#endif /* EXTEND */
            else
            {
                showErr(MUST_KEYWORD);
                assert(strval.size()>0);
                pf.unget();
                goto again;
            }
        }
        else
        {
            showErr(PERCENT_ERROR);
            pf.unget();
            goto again;
        }
        break;

        /* 处理单字符 */
    case '\'':
    {
        register sint32 code=0;
        c=pf.get();
        if('\\'==c)
        {
            c=pf.get();
            if(c>='0' && c<='7')
            {
                while(c>='0' && c<='7')
                {
                    code=code*8+(c-'0');
                    if(code >=256 || code <0)
                        showErr(LITERAL_ERROR);
                    c=pf.get();
                }
                pf.unget();
            }
            else if('\"'==c)    code='\"';
            else if('\\'==c)    code='\\';
            else if('\''==c)    code='\'';
            else if('n'==c)     code='\n';
            else if('t'==c)     code='\t';
            else if('r'==c)     code='\r';
            else if('f'==c)     code='\f';
            else if('a'==c)     code='\007';
            else if('b'==c)     code='\b';
            else if('v'==c)     code=013;
            else if ('x'==c || 'X'==c)
            {
                c = pf.get();
                while ((c <= '9' && c >= '0')
                    || (c >= 'a' && c <= 'z')
                    || (c >= 'A' && c <= 'Z'))
                {
                    code *= 16;
                    if (c <= '9' && c >= '0')
                        code += c - '0';
                    else if (c >= 'a' && c <= 'z')
                        code += c - 'a' + 10;
                    else if (c >= 'A' && c <= 'Z')
                        code += c - 'A' + 10;
                    if (code >= 256 || code<0)/* JF this said if(c>=128) */
                        showErr(LITERAL_ERROR);
                    c=pf.get();
                }
                pf.unget();
            }
            else
            {
                errorstring='\'';
                errorstring+=(uchar8)c;
                errorstring+='\'';
                showErr(ESCAPE_ERROR);
            }
        }
        else
        {// 如果单引号中无转义,如形如:'y'
            if('\''==c )
            {
                errorstring=" \'\'\'";
                showErr(ESCAPE_ERROR);
            }
            code=c;
        }
        c=pf.get();
        if('\'' != c)
        {
            showErr(LACK_QUOTE);
        }

        // 将各转换字符转换为可输出的字符串形式,如 '\n' 转换为 '\\n'
        strval='\'';
        if                    ('\''==code)
            strval+="\\'";
        else                if('\"'==code)
            strval+="\\\"";
        else                if('\\'==code)
            strval+="\\\\";
        else                if(code >=040 && code !=0177)
            strval+=(uchar8)code;
        else                if('\n'==code)
            strval+="\\n";
        else                if('\t'==code)
            strval+="\\t";
        else                if('\f'==code)
            strval+="\\f";
        else                if('\v'==code)
            strval+="\\v";
        else                if('\b'==code)
            strval+="\\b";
        else 
        {
            strval+=(uchar8)(code/0100 + '0');
            strval+=(uchar8)((code/010 & 07)+'0');
            strval+=(uchar8)((code & 07) + '0');
        }
        strval+='\'';

        numval=code;
        //////////
        return ASC;
        
    }// case '\'':

    case ':':   case '|':   case ';':
    case '{':   case '}':   case '<':
    case '>':
        strval=(char)c;
        return c;
        break;

#ifdef _DEBUG
    case '\n':
        ++lineno;
    case ' ':   case '\t':  case '\f':
        //cout<<lineno;
        //assert(0);
        goto again;
        break;
#endif

    case ENDOFFILE:
        return END;
    default:
        errorstring=(char)c;
        showErr(UNKNOWN_LITERAL);
        goto again;
        break;
    }
    assert(0);
    goto again;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -