关于Basic程序解释器及编译原理的简单化(2)---C++封装好的Basic解释器

    技术2022-05-11  121

    这是CMake的源代码.主要负责词汇的提取你可以调用它的CMake::get_token(),返回个CToken的类.

    /// Make.h///

    enum token_types{DELIMITER,VARIABLE,NUMBER,COMMAND,             STRING,QUOTE,FINISHED,NONE,ENTER};         // 标记类型集合

    #define TOKEN_MAX 80#define STRDELIMITER "+-*^/=;(),><" // 符号集合#define DIM     11 // Dim#define AS      12 // As#define INTEGER 13 // Integer#define PRINT   14 // Print

    class CToken {public: char token[TOKEN_MAX]; int token_type; int tok;};

    class CMake  {public: CMake(char *Prog,int Proglength); virtual ~CMake();public:    char *prog; int proglength; int isdelim(char c);     // 如果是运算符号返回1,不是则返回0 int iswhite(char c);     // 是空格返回1,不是则返回0 int look_up(char *c);    // 返回COMMAND类型,c是COMMAND字符串的指针 CToken get_token(void);   // 得到标记 int findchar(char *str,char ch); // 从str里找到ch,返回其在str里的引索;如果str里没有ch,则返回-1};

    /

     

     

    // Make.cpp: implementation of the CMake class.////

    #include "stdafx.h"#include "Make.h"

    //// Construction/Destruction//

    CMake::CMake(char *Prog,int Proglength){  proglength=Proglength;  prog=new char[Proglength+1];  strcpy(prog,Prog);}

    CMake::~CMake(){ }

    CToken CMake::get_token(void) { register char *temp; CToken m_token;    m_token.token_type=0; m_token.tok=0; temp=m_token.token; if(*prog=='/0') {  *m_token.token='/0';  m_token.tok=0;  m_token.token_type=FINISHED;  return m_token; } while(iswhite(*prog)) ++prog;     if(*prog=='/r') // 如果是换行符 {  m_token.token[0]=*prog;  m_token.token[1]='/0';  m_token.token_type=ENTER;  prog++;  return m_token; } if( isdelim(*prog)) // 如果找得到运算符号标记 {    *m_token.token=*prog;     *(m_token.token+1)='/0';    m_token.tok=0;    m_token.token_type=DELIMITER;    prog++;    return m_token;            // 譬如 token[0]='+' token[1]='/0'; }

     if(*prog=='"')   // 如果是字符串 {  prog++;  int i=0;  while(*prog!='"' && *prog!='/r')  {   m_token.token[i]=*prog;   i++;   prog++;  }  prog++;  m_token.token[i]='/0';  m_token.token_type=QUOTE;  return m_token; }

     if( isdigit(*prog)) // 如果找到数字标记 {  int i=0;  while(isdigit(*prog) && i<TOKEN_MAX) // 小于token最长为80个字符  {   m_token.token[i]=*prog;   i++;   prog++;  }  m_token.token[i]='/0';  m_token.token_type=NUMBER;  return m_token; } if( isalpha(*prog)) // 如果是命令COMMAND或是一般标记STRING {  int i=0;  while(!isdelim(*prog) && *prog!=' ') // 不能是运算符号和空格  {   m_token.token[i]=*prog;   i++;   prog++;  }  m_token.token[i]='/0';  if(look_up(m_token.token)) // 如果能查到它是命令COMMAND  {   m_token.token_type=COMMAND;   m_token.tok=look_up(m_token.token);  }  else  {   m_token.token_type=STRING;  }  return m_token; } 

     m_token.token_type=NONE; prog++; return m_token;}

    int CMake::iswhite(char c){ if(c==' '||c=='/t') return 1; else return 0;}

    int CMake::isdelim(char c){ if( findchar(STRDELIMITER,*prog) >= 0 || c==9 || c=='/r' || c==0)  return 1; return 0;}

    int CMake::findchar(char *str,char ch) { int length=strlen(str); if(length>0) {  for(int i=0;i<length;i++)   if(str[i]==ch)      return i;   return -1; } else return -1;}

    int CMake::look_up(char *c){ if(strcmp(c,"print")==0)  return PRINT;    if(strcmp(c,"Integer")==0)  return INTEGER; if(strcmp(c,"Dim")==0)  return DIM; if(strcmp(c,"As")==0)  return AS;

        return 0;}

    这是执行代码的CExecutable封装

    //// CExecutable.h

    class CintMember{public: char name[64]; int value;};

    class CExecutable  {public: CExecutable(vector <CToken> tokens); virtual ~CExecutable(); void Run();private: vector <CToken> m_tokens; file://装所有标记的数据库 vector <CintMember> m_intArray; file://装所有int类型的变量 void Run_Print(int *index); file://*index是重要的m_tokens里的指针 void Run_Dim(int *index); file://~~  void Run_Assignment(int *index);// 赋值语句 file://Ai是辅助的意思,Ai_*()是辅助函数 int Ai_GetNextValue(void* result,int type,int *index); file://得到代数式的值result int Ai_GetVarNo(char *name,int *result,int type);//得到变量在Array中的引索result void get_exp(int *result,int *index); void level2(int *result,int *index); void level3(int *result,int *index); void level4(int *result,int *index); void level5(int *result,int *index);    void level6(int *result,int *index); void primitive(int *result,int *index); void arith(char o,int *r,int *h); void serror(int error); int look_up(char *c); int find_var(char *var_name,void *value); // 查找变量,将变量值装在*value int Isvar(char *name); // 看name是否是变量,返回变量类型 0:什么都不是,1:Integer,2:string};

    /

    // Executable.cpp: implementation of the CExecutable class.////

    #include "stdafx.h"#include "Executable.h"

    //// Construction/Destruction//

    CExecutable::CExecutable(vector <CToken> tokens){ m_tokens=tokens;}

    CExecutable::~CExecutable(){ m_intArray.clear(); m_tokens.clear();}

    void CExecutable::Run(void){   for(int i=0;i<=m_tokens.size()-1;i++)//注意:i是个十分重要的读取指针   {  if(m_tokens.at(i).token_type==COMMAND)  {   switch(m_tokens.at(i).tok) file://tok表示是什么命令   {   case PRINT: Run_Print(&i);         break;   case DIM:   Run_Dim(&i);            break;   default:   break;   }  }  file://赋值语句一定要在最后来判断,因为这样如果是if后的条件判断就可以在  file://前面的if命令中跳过  if(*m_tokens.at(i).token=='=') file://如果是赋值语句   Run_Assignment(&i);   }}

    void CExecutable::Run_Print(int *index) file://*index是m_tokens里的指针{ if(*index<m_tokens.size()-1) // 如果下面还有token {     if(m_tokens.at((*index)+1).token_type==ENTER) file://如果接下来是命令  {   printf("/n");   return;  }  (*index)++;     int token_type=m_tokens.at(*index).token_type;  if(Isvar(m_tokens.at(*index).token)) file://如果接下来是变量   token_type=VARIABLE;           switch(token_type)  {  case QUOTE: file://如果是要打印字符串   {    printf(m_tokens.at(*index).token);    return;   }  case VARIABLE:  file://打印代数式 type只要不是COMMAND就是可以当代数式处理  case NUMBER:  case DELIMITER:        {    int result;          Ai_GetNextValue(&result,INTEGER,index);    printf("%d",result);    return;   }  default: printf("/n");     return;  } } printf("/n");  }

    void CExecutable::Run_Dim(int *index) file://~~{ int i=*index; if(i<m_tokens.size()-1)//~~  if(m_tokens.at(i+1).token_type==STRING)  {   if(i<m_tokens.size()-3) file://如果下面还应该有 变量名,As,类型 三个tokens   {    CintMember member;    if(m_tokens.at(i+2).token_type==COMMAND &&      m_tokens.at(i+2).tok==AS) file://如果接下来的token是As    {    if(m_tokens.at(i+3).token_type==COMMAND)//接下来是变量类型     switch(m_tokens.at(i+3).tok) file://看看是什么变量类型     {          case INTEGER: // 如果是Integer类型        strcpy(member.name,m_tokens.at(i+1).token);        member.value=0;        m_intArray.push_back(member);        *index+=3; // 将m_tokens里的指针跳3个        break;          default:             break;     }    }   }  }}

    void CExecutable::Run_Assignment(int *index) file://index必须指到'='的token{ int var_type=Isvar(m_tokens.at(*index - 1).token); if(!var_type) // 如果等号前面不是个变量 {  serror(0);  return; } switch(var_type) { case INTEGER:  {   int Var_No,value;   if(!Ai_GetVarNo(m_tokens.at(*index-1).token,&Var_No,INTEGER))               break;   (*index)++;            if(!Ai_GetNextValue(&value,INTEGER,index))      break;   m_intArray.at(Var_No).value=value;   break;  } default: break; }}

     

    int CExecutable::Ai_GetNextValue(void *result,int type,int *index) file://index指到代数式的第一个token{ switch(type) { case INTEGER: get_exp((int*)result,index);            return 1; default:    return 0; }

    }

    int CExecutable::Ai_GetVarNo(char *name,int *result,int type){ switch(type) { case INTEGER:  {   if(m_intArray.size()==0)    return 0;   for(int i=0;i<=m_intArray.size()-1;i++)    if(!strcmp(name,m_intArray.at(i).name))     *result=i;    return 1;  } default: return 0; }

    }void CExecutable::get_exp(int *result,int *index){    if (!*m_tokens.at(*index).token) {        serror(2);        return;    }    level2(result,index);     }

    /* add or subtract two terms */void CExecutable::level2(int *result,int *index){    register char op;    int hold;    level3(result,index);    while ((op = *m_tokens.at(*index).token) =='+' || op == '-')   {        (*index)++;        level3(&hold,index);        arith(op,result,&hold);    }}

    /* multiply or divide two factors */void CExecutable::level3(int *result,int *index){ register char op;    int hold;    level4(result,index);    while ((op = *m_tokens.at(*index).token) == '*' || op == '/' || op == '%')   {        (*index)++;        level3(&hold,index);        arith(op,result,&hold);    }}

    /* process integer exponent */void CExecutable::level4(int *result,int *index){ register char op;    int hold;    level5(result,index);    if ((op = *m_tokens.at(*index).token) == '^')  {        (*index)++;        level5(&hold,index);        arith(op,result,&hold);    }}             

    /* is a unary + or - */              void CExecutable::level5(int *result,int *index){    register char op;    op = 0;    if ((m_tokens.at(*index).token_type==DELIMITER) &&   *m_tokens.at(*index).token == '+' ||   *m_tokens.at(*index).token == '-' )   {        op = *m_tokens.at(*index).token;        (*index)++;    }    level6(result,index);    if (op)    if(op=='-')   *result=-(*result);}               

    /* process parenthesized expression */                void CExecutable::level6(int *result,int *index){ if ((*m_tokens.at(*index).token == '(') && (m_tokens.at(*index).token_type == DELIMITER))   {        (*index)++;        level2(result,index);        if (*m_tokens.at(*index).token!=')')            serror(1);        (*index)++;    }    else         primitive(result,index);}

    /* find value of number or variable */void CExecutable::primitive(int *result,int *index){ int token_type=m_tokens.at(*index).token_type;    if(Isvar(m_tokens.at(*index).token))    token_type=VARIABLE;    switch (token_type)  {        case VARIABLE:            find_var(m_tokens.at(*index).token,result);            (*index)++;            return;        case NUMBER:            *result = atoi(m_tokens.at(*index).token);            (*index)++;            return;        default:            serror(0);    }}

    int CExecutable::find_var(char *var_name,void *value){ for(int i=0;i<=m_intArray.size()-1;i++)  if(!strcmp(var_name,m_intArray.at(i).name))  {   int *int_value=(int *)value;   *int_value=m_intArray.at(i).value;   return 1;  }    return 0;}

    int CExecutable::Isvar(char *name){ if(m_intArray.size()==0)  return 0; for(int i=0;i<=m_intArray.size()-1;i++)  if(!strcmp(name,m_intArray.at(i).name))        return INTEGER; return 0;}

    /* perform the specified arithmetic */void CExecutable::arith(char o,int *r,int *h){    /*register*/ int t,ex;        switch (o)  {        case '-':            *r = *r-*h;            break;        case '+':            *r = *r+*h;            break;        case '*':            *r = *r**h;            break;        case '/':            *r = (*r)/(*h);            break;        case '%':            *r = (*r)%(*h);            break;        case '^':            ex = *r;            if (*h==0)  {                *r = 1;                break;            }            for (t=*h-1;t>0;--t)  *r=(*r)*ex;            break;    }}

    int CExecutable::look_up(char *c){ if(strcmp(c,"print")==0)  return PRINT;    if(strcmp(c,"Integer")==0)  return INTEGER; if(strcmp(c,"Dim")==0)  return DIM; if(strcmp(c,"As")==0)  return AS;    return 0;}

    void CExecutable::serror(int error){ char *e[] = {        "syntax error",        "unbalanced parentheses",        "no expression present",        "equal sign expected",        "not a variable",        "label table full",        "duplicate label",        "undefined label",        "THEN expected",        "TO expected",        "too many nested FOR loops",        "NEXT without FOR",        "too many nested GOSUB",        "RETURN without GOSUB"    };

        printf ("%s/n",e[error]);}


    最新回复(0)