構造使用類C語言的指令碼引擎(4)文法分析

來源:互聯網
上載者:User
構造使用類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]);

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.