构造使用类C语言的脚本引擎(4)

构造使用类C语言的脚本引擎(4)

作者 :kevin_qing

转贴请注明

同上一章一样,语法分析部分也不准备使用yacc直接生成代码,而是只使用yacc的生成的分析表。

BNF:

%token ID IF ELSE SWITCH GOTO RETURN NUMBER STRING MAIN
%token ADD_OP MUL_OP ASSIGN_OP CMP_OP LOGIC_OP1 LOGIC_OP2
%token LPAREN RPAREN LBRACE RBRACE COLON COMMA SEMI

%%
PROG
 : MAIN LPAREN RPAREN CPD_SMT
 ;

CPD_SMT
 : LBRACE SMT_SEQ RBRACE
 ;

SMT_SEQ
 : LB_SMT
 | SMT_SEQ LB_SMT
 ;

LABLE : ID COLON
 ;

LB_SMT
 : SMT
 | LABLE SMT
 ;
SMT
 : EXPR SEMI
 | SEMI
 | GOTO ID SEMI
 | RETURN SEMI
 | IF LPAREN EXPR RPAREN SMT
 | IF LPAREN EXPR RPAREN SMT ELSE SMT
 | SWITCH LPAREN EXPR RPAREN LBRACE CASES RBRACE
 | CPD_SMT
 ;

CASE : NUMBERS COLON SMT
 ;

CASES : CASE
 | CASES CASE
 ;

NUMBERS : ADD_OP NUMBER
 | NUMBER
 ;

STRINGS : STRING
 | STRINGS STRING
 ;

PAM_LIST
 : EXPR
 | PAM_LIST COMMA EXPR
 ;

PRI_EXPR
 : ID
 | NUMBERS
 | STRINGS
 | LPAREN EXPR RPAREN
 ;
POST_EXPR
 : PRI_EXPR
 | ID LPAREN RPAREN
 | ID LPAREN PAM_LIST RPAREN
 ;
 
MUL_EXPR
 : POST_EXPR
 | MUL_EXPR MUL_OP POST_EXPR
 ;

ADD_EXPR
 : MUL_EXPR
 | ADD_EXPR ADD_OP MUL_EXPR
 ;

CMP_EXPR
 : ADD_EXPR
 | ADD_EXPR CMP_OP ADD_EXPR
 ;

LOGIC_EXPR
 : CMP_EXPR
 | LOGIC_EXPR LOGIC_OP2 CMP_EXPR
 | LOGIC_OP1 CMP_EXPR
 ;

EXPR
 : LOGIC_EXPR
 | ID ASSIGN_OP EXPR
 ;


 

%%

 

使用bison++ -o o -v bnf.txt编译后生成o.output和其他文件

我只使用o.output的输出.

o.output的部分内容

State 69 contains 1 shift/reduce conflict. //69条有一个关于悬挂else的冲突,这里yacc默认的状态转移已经是正确的了,就不需要再做其他处理

Grammar

语法规则,//我通过对此的识别生成规约函数

---------------
rule 1    PROG -> MAIN LPAREN RPAREN CPD_SMT
rule 2    CPD_SMT -> LBRACE SMT_SEQ RBRACE
rule 3    SMT_SEQ -> LB_SMT
--------------

状态转移,程序主要通过对状态转移行的识别来构建分析表.

左边为输入的标志符,右边为动作。

------------------------

state 0

    MAIN shift, and go to state 1

    PROG go to state 80
-------------------------

动作可能有4种

shift, and go to state [n]

reduce using rule [n] ...

go to state [n]

accept

通过状态转移表构造分析表。

在这里我是写了一个小程序实现的自动生成分析表和规约函数。

LPCSTR LableName[]={ "ID","IF","ELSE","SWITCH","GOTO","RETURN","NUMBER","STRING","MAIN",
"ADD_OP","MUL_OP","ASSIGN_OP","CMP_OP","LOGIC_OP1","LOGIC_OP2",
"LPAREN","RPAREN","LBRACE","RBRACE","COLON","COMMA","SEMI",

"PROG","CPD_SMT","SMT_SEQ","LABLE","LB_SMT","SMT","CASE","CASES",
"NUMBERS","STRINGS","PAM_LIST","PRI_EXPR","POST_EXPR","MUL_EXPR","ADD_EXPR","CMP_EXPR","LOGIC_EXPR","EXPR","$END"
};

#define CNT (sizeof(LableName)/sizeof(LableName[0]))
char* getToken(char* &p){
 while(*p){
  if((*p==' ')||(*p=='/t')){
   ++p;
  }else{
   char *r=p;
   while(*p){
    if(('/n'==*p)||('/t'==*p)|| (' '==*p)){
     *p=0;
     ++p;
     break;
    }else{
     ++p;
    }
   }
   return r;

  }

 };
 return NULL;
 
}
bool sm(LPCSTR s,LPCSTR d){
 if(s&&d){
  return 0==strcmp(s,d);
 }
 return false;
}

#define m(x) (sm(getToken(p),x))
void yy2ini(){
 FILE* fp=fopen("lalr分析表.txt","r");
 FILE* fpo=fopen("lalr.ini","w");
 FILE* fp1=fopen("Rfun.c","w");
 char tmp[4096];
 while(fgets(tmp,4096,fp)){
  char* p=tmp;
  char* r=getToken(p);
  int i;
  if(sm(r,"state")){
   r=getToken(p);
   if(r)
   {
    i=atoi(r);
    fprintf(fpo,"[S%d]/n",i);
   }
  }else if(sm(r,"rule")){
   char* r1=getToken(p);
   if(r1){
    int n=atoi(r1);
    char* tmp[1024];
    int i=0;
    r=getToken(p);
    if(r)if(m("->")){
     while(tmp[i]=getToken(p))++i;
     fprintf(fp1,"//Rule[%d] %s -> ",n,r);
     for(int j=0;j<i;++j)
      fprintf(fp1,"%s ",tmp[j]);
     fprintf(fp1,
      "/nvoid Reduce%d(){/n",n);
     for(int j=0;j<i;++j)
      fprintf(fp1,
      " assert(TokenStack[%d]->tokenType==%s);/n",-j-1,tmp[i-j-1]);
     if(i>1)
      fprintf(fp1,
      " TokenStack.pop(%d);/n",i-1);
     fprintf(fp1,
      " TokenStack[-1]->tokenType=%s;/n"
      " StateStack.pop(%d);/n"
      "}/n/n",r,i);

    }
    

   }
           
  }else{
   char* r1=getToken(p);
   if(sm(r1,"shift,"))
   {
    if(m("and")&&m("go")&&m("to")&&m("state")){
     r1=getToken(p);
     if(r1){
      i=atoi(r1);
      fprintf(fpo,"%s=S%d/n",r,i);
     }
    }
   }else if(sm(r1,"go")){
    if(m("to")&&m("state")){
     r1=getToken(p);
     if(r1){
      i=atoi(r1);
      fprintf(fpo,"%s=G%d/n",r,i);
     }
    }
   }else if(sm(r1,"reduce"))//reduce using rule
   {
    if(m("using")&&m("rule")){
     r1=getToken(p);
     if(r1){
      i=atoi(r1);
      fprintf(fpo,"%s=R%d/n",r,i);
     }

    }
   }

  }
 }
 fclose(fp);
 fclose(fpo);

 fprintf(fp1,"typedef void REDUCE();/n"
  "REDUCE* Reduce[]={/n");
 for(int i=1;i<44;++i)
  fprintf(fp1,"/t&Reduce%d,/n",i);

 fprintf(fp1,"};/n");
 fclose(fp1);
}

 

 

主程序(lalr分析)

void main(){
 SCCompiler sc;
 sc.init();
 sc.open("test.sc");
 StateStack.push(0);
 TokenStack.push(new Token(START,0));
 while(1)
  try{
   Token*p=sc.getToken();

//   printf("Get %s @%d/n",LableName[p->tokenType],p->line);
rescan:
   if((StateStack[ST_TOP]==80)&&p->tokenType==ENDOFSTREAM)
    break;
   uint32_t r=LalrTab[StateStack[ST_TOP]][p->tokenType&0xffff];
   switch(r&0xf0000){
   case SMASK:
    TokenStack.push(p);
    StateStack.push(r&0xffff);
    break;
   case RMASK:{
    uint32_t id=r;
    do{
     id&=0xffff;
     Reduce[id-1]();
     id=LalrTab[StateStack[ST_TOP]][TokenStack[ST_TOP]->tokenType&0xffff];
    }while(ISR(id));
    if(ISG(id)){
     StateStack.push(id&0xffff);
     //StateStack[0]=(id&0xffff);
     goto rescan;
    }else
     assert(false);
        }
   default:
    assert(false);
   }
  }catch(int err){  printf("EOF %d",err);break; }

  printf("Accept/n");
  printf("StateStack  %d/n",StateStack[ST_TOP]);

 


你可能感兴趣的:(c,脚本,语言,FP,引擎,Numbers)