接着昨天的词法分析器,语法分析主要是将从词法分析那里得来的记号构成一棵语法树。这次我将作案的词法分析部分的代码稍作了修改,让他更适合语法分析器。我使用的是自下而上的分析法,针对算符优先文法的产生式构造语法树。 以下的代码只支持7种节点——加减乘除,标识符,数字,表达式。想要加入其他节点,在opprio数组中加入优先级。 ////////////////////////////////Parse.h////////////////////////////////// #ifndef _PARSE_H_ #define _PARSE_H_ #include "lexical.h"
//算法优先文法中优先级关系枚举 typedef enum {LS, GT, EQ,UN} Priority; //移进归约算法中使用到的栈节点结构(双向链表) typedef struct _pstacktoken { LexToken *ptoken; struct _pstacktoken *pr; struct _pstacktoken *nt; struct _pstacktoken *child; }PStackToken; void PStackPush(LexToken *t); LexToken* PStackPop();
//产生式链表节点结构(单向链表) typedef struct _generator {LexTokenType *gen; int size; struct _generator *nt;} Generator; PStackToken* Parse(char *Source);
#endif//_PARSE_H ////////////////////////////////////////Parse.c///////////////////////////// #include "Parse.h" #include <malloc.h> #include <string.h> #include <stdarg.h> #include <stdio.h>
//各个运算符之间的优先级定义 #define OPNUM 7 Priority opprio[OPNUM][OPNUM]={ {GT,GT,LS,LS,LS,LS,GT,}, {GT,GT,LS,LS,LS,LS,GT,}, {GT,GT,GT,GT,LS,LS,GT,}, {GT,GT,GT,GT,LS,LS,GT,}, {GT,GT,GT,GT,UN,UN,GT,}, {GT,GT,GT,GT,UN,UN,GT,}, {LS,LS,LS,LS,LS,LS,EQ,}, }; Priority PrioCmp(LexTokenType first, LexTokenType second)//这段函数被优化代码替代 { if (first>=OPNUM || second>=OPNUM) return UN; return opprio[first][second]; }
PStackToken *PSbot = NULL;//栈底指针 PStackToken *PStop = NULL;//栈顶指针 //int PSnum = 0;//栈元素个数 void PStackPush(LexToken *t) { static int size = sizeof(PStackToken); PStackToken *p = (PStackToken*)malloc(size);//不检查合法性 p->ptoken = t;//不对t的合法性检查 if (!PSbot)//第一个节点 { PSbot = PStop = p; p->pr = p->nt = NULL; } else { PStop->nt = p; p->pr = PStop; p->nt = NULL; PStop = p; } p->child = NULL; } LexToken* PStackPop() { LexToken *p = PStop->ptoken; PStackToken *last = PStop; if (PStop==NULL)//如果已无元素可弹出 return NULL; PStop = PStop->pr; PStop->nt = NULL; free(last); return p; }
Generator *GLhead = NULL; Generator *GLend = NULL; void AddGen(int num, ...) { static int sizegen = sizeof(Generator); static int sizetype = sizeof(LexTokenType); Generator *pGen = (Generator*)malloc(sizegen); int i; va_list pArgList; va_start (pArgList, num); pGen->size = num; pGen->gen = (LexTokenType*)malloc(sizetype); pGen->nt = NULL; for (i=0; i<num; i++) { pGen->gen[i] = va_arg(pArgList, LexTokenType); } va_end (pArgList); if (!GLhead) { GLhead = pGen; GLend = pGen; } else { GLend->nt = pGen; GLend = pGen; } } void InitGenerator() { AddGen(3,EXPRESSION,PLUS,EXPRESSION); AddGen(3,EXPRESSION,MINUS,EXPRESSION); AddGen(3,EXPRESSION,MULTI,EXPRESSION); AddGen(3,EXPRESSION,DIVIDE,EXPRESSION); AddGen(1,IDENTI); AddGen(1,NUMBER); }
PStackToken *PSnow = NULL; LexToken *gettoken = NULL; PStackToken *PStail = NULL; PStackToken* Parse(char *Source) { static int sizeLexToken = sizeof(LexToken); Generator *pgennow = NULL;//查找产生式时使用 LexToken *pstart = (LexToken*)malloc(sizeLexToken);//不检查合法性 Priority PrioCmpRlt = UN; InitGenerator(); pstart->strName = NULL; pstart->type = JINGHAO; PStackPush(pstart); while (gettoken = GetNextToken(Source)) { if (PStop->ptoken->type == EXPRESSION) { PSnow = PStop->pr; } else { PSnow = PStop; } while ((PrioCmpRlt = PrioCmp(PSnow->ptoken->type, gettoken->type)) == GT)//PSnow未作检查,找到最左素短语尾部 { while (1)//查找最左素短语头部 { PStail = PSnow; PSnow = PSnow->pr; if (PSnow->ptoken->type == EXPRESSION)//未做合法性检查 { PSnow = PSnow->pr; } if (PrioCmp(PSnow->ptoken->type, PStail->ptoken->type) == LS) {//归约 int i; PStackToken *pst; pgennow = GLhead; while(pgennow) { pst = PSnow->nt; for (i=0; i<pgennow->size && pst!=PStop->nt; i++) { if (pst->ptoken->type != pgennow->gen[i]) break; pst = pst->nt; } if(i==pgennow->size && pst==PStop->nt)//找到了产生式 { LexToken *pExp = (LexToken*)malloc(sizeof(LexToken)); pst = PSnow->nt; pExp->strName = NULL; pExp->type = EXPRESSION; PStop = PSnow; PStackPush(pExp);//插入一个Expression节点 PStop->child = pst;//为该节点建立树 pst->pr = NULL; break; } pgennow = pgennow->nt; } //在这里考虑无法归约的情况 } break; } // break; } if (PrioCmpRlt == LS) { PStackPush(gettoken); continue; } if (PrioCmpRlt == EQ) { if (PSnow->ptoken->type == JINGHAO) { //识别 break; } else { PStackPush(gettoken); continue; } } } return PStop; }

|