借助YACC编写词法分析以及语法分析,输出语法树

词法分析

1.lex.l文件

%{
#include "stdio.h"
#include "trans.tab.h"//一定要添加该头文件,和后面的语法分析配合
%}
DIGIT [0-9] //申明DIGIT的正则表达式
%%//以上均是申明
{DIGIT}+ {  yylval = atoi(yytext); return NUM;} /*printf("int: %s(%d)\n",yytext,atoi(yytext));}*/
\n { return END; }
"+" { return ADD; }
"-" { return MINUS;}
"*" { return MUL; }
"/" { return DIV;}
%%//以上均是正则表达式
int yywrap() 
{ return 1; }

如果只要词法分析,代码可以有如下修改

%{
#include "stdio.h"
#include "trans.tab.h"//一定要添加该头文件,和后面的语法分析配合
%}
DIGIT [0-9] //申明DIGIT的正则表达式
%%//以上均是申明
{DIGIT}+ {  yylval = atoi(yytext); return NUM;} /*printf("int: %s(%d)\n",yytext,atoi(yytext));}*/
\n { return END; printf("换行符");}
"+" { return ADD; printf("运算符:“+”");}
%%//以上均是正则表达式
int yywrap() 
{ return 1; }

 

 

词法分析

1.文法

input   ->   input line |

line     ->   '\n' | E '\n'

E        ->   T | E add T | E minus T

T         ->   F | T mul F | T div F

F         ->   (E) | NUM

 2.创建trans.y文件

         申明部分


%{
    #include "lex.yy.c"
    #include 
    #include 
    #include 
    #include 
    //语法树的结构
    typedef char* ElemType; 

	int i;
    typedef struct BiTNode{
        ElemType data;
        struct BiTNode *lChild, *mChild, *rChild;
    }BiTNode, *BiTree;

    typedef struct Node{
        BiTNode *data;
        struct Node *next;
    }Node, *LinkedList;

    void yyerror (char const *);
//创建链表
LinkedList LinkedListInit()    
{    
     Node *L;    
     L = (Node *)malloc(sizeof(Node));
     L->next = NULL;
     return L;
}

//插入节点,头插法
LinkedList LinkedListInsert(LinkedList L,BiTNode *x)    
{    
     Node *pre;
     pre = L;
     Node *p;
     p = (Node *)malloc(sizeof(Node));    
     p->data = x;     
     p->next = pre->next;    
     pre->next = p;    
     return L;                               
}

//创建叶子
BiTree createLeaf(ElemType root)
{

     BiTree T = (BiTree)malloc(sizeof(BiTNode));
     if (T != NULL) {
               T->data = root;
               T->lChild = NULL;
               T->mChild = NULL;
               T->rChild = NULL;
     }
     else exit(-1);
     return T;
}

BiTree createTree(ElemType root, BiTree lleaf, BiTree mleaf, BiTree rleaf)
{

     BiTree T = (BiTree)malloc(sizeof(BiTNode));
     if (T != NULL) {
               T->data = root;
               T->lChild = lleaf;
               T->mChild = mleaf;
               T->rChild = rleaf;
     }
     else exit(-1);
     return T;
}

//后序遍历
void TraverseBiTree(BiTree T)
{
     if (T == NULL) return ;
     TraverseBiTree(T->lChild);
     TraverseBiTree(T->mChild);
     TraverseBiTree(T->rChild);
     if(T->data != " ") printf("%s ", T->data);
}

//变量的申明,全局变量必须赋初值
    LinkedList list = NULL;
    LinkedList head = NULL;
    BiTree T, TL, TM, TR;
    
%}

//从词法分析中提取出来
%token END
%token NUM
%token ADD
%token MUL
%token MINUS
%token DIV
%% /* Grammar rules and actions follow.  */

  

      文法部分

input:
  /* empty */ 
| input line 
;
line:
  '\n'          { }
| exp END      { head = list->next;
                  T = head->data;
                  printf("Traverse BiTree:\n");
                  TraverseBiTree(T); 
				  printf("\n");
				  printf ("answer:%d\n", $1);}
;
exp:
  term           { $$ = $1;   printf("E->T\n");  
                  head = list->next;
                  TL = head->data;
                  TM = createLeaf(" ");
                  TR = createLeaf(" ");
                  T = createTree("E", TL, TM, TR);
                  list->next = head->next;
                  LinkedListInsert(list, T);   }   
| exp ADD term   { $$ = $1 + $3; printf("E->E+T\n");  
                  head = list->next;
                  TL = (head->next)->data;
                  TM = createLeaf("+");
                  TR = head->data;
                  T = createTree("E", TL, TM, TR);
                  list->next = (head->next)->next;
                  LinkedListInsert(list, T);    } 
| exp MINUS term { $$ = $1 - $3; printf("E->E-T\n");  
                  head = list->next;
                  TL = (head->next)->data;
                  TM = createLeaf("+");
                  TR = head->data;
                  T = createTree("E", TL, TM, TR);
                  list->next = (head->next)->next;
                  LinkedListInsert(list, T); }				  
;
term:
  factor          { head = list->next; printf("T->F\n"); 
                    TL = head->data;
                    TM = createLeaf(" ");
                    TR = createLeaf(" ");
                    T = createTree("T", TL, TM, TR);
                    list->next = head->next;
                    LinkedListInsert(list, T);}
| term MUL factor { $$ = $1 * $3; printf("T->T*F\n"); 
                    head = list->next;
                    TL = (head->next)->data;
                    TM = createLeaf("*");
                    TR = head->data;
                    T = createTree("T", TL, TM, TR);
                    list->next = (head->next)->next;
                    LinkedListInsert(list, T);    } 
| term DIV factor { $$ = $1 / $3; printf("T->T/F\n"); 
                    head = list->next;
                    TL = (head->next)->data;
                    TM = createLeaf("/");
                    TR = head->data;
                    T = createTree("T", TL, TM, TR);
                    list->next = (head->next)->next;
                    LinkedListInsert(list, T);    
}
;
factor:
  '('exp')'
| NUM             {
					printf("F->%d\n", $1);
					int num = $1;
					int len = 0;
					char* temp1 = (char*)malloc(sizeof(char)*10);//c语言中指针,数组等必须要赋给空间
					char* temp2 = (char*)malloc(sizeof(char)*10);
					while(num)
					{
						temp1[len] = '0'+num%10;
						num /= 10;
						len++;
					}
					for(i = 0; i < len; ++i)
					{
						temp2[i] = temp1[len-i-1];
					}
					temp2[len] = '\0';
                    TL = createLeaf(temp2);
                    TM = createLeaf(" ");
                    TR = createLeaf(" ");
                    T = createTree("F", TL, TM, TR);
                    LinkedListInsert(list, T);}
;
%%

      主控程序部分

int
main(void)
{
  list = LinkedListInit();
  T = NULL, TL = NULL, TM = NULL, TR = NULL;
  /*yydebug = 1;*/    /*bison -d -t*/ /*bison -d -v*/
  yyparse();
  return 0;
}

/* Called by yyparse on error.  */
void
yyerror (char const *s)
{
  fprintf (stderr, "%s\n", s);
}

整个trans.y文件

/* Reverse polish notation calculator.  */

%{
    #include "lex.yy.c"
    #include 
    #include 
    #include 
    #include 
    typedef char* ElemType; 

	int i;
    typedef struct BiTNode{
        ElemType data;
        struct BiTNode *lChild, *mChild, *rChild;
    }BiTNode, *BiTree;

    typedef struct Node{
        BiTNode *data;
        struct Node *next;
    }Node, *LinkedList;

    void yyerror (char const *);
//创建链表
LinkedList LinkedListInit()    
{    
     Node *L;    
     L = (Node *)malloc(sizeof(Node));
     L->next = NULL;
     return L;
}

//插入节点,头插法
LinkedList LinkedListInsert(LinkedList L,BiTNode *x)    
{    
     Node *pre;
     pre = L;
     Node *p;
     p = (Node *)malloc(sizeof(Node));    
     p->data = x;     
     p->next = pre->next;    
     pre->next = p;    
     return L;                               
}

//创建叶子
BiTree createLeaf(ElemType root)
{

     BiTree T = (BiTree)malloc(sizeof(BiTNode));
     if (T != NULL) {
               T->data = root;
               T->lChild = NULL;
               T->mChild = NULL;
               T->rChild = NULL;
     }
     else exit(-1);
     return T;
}

BiTree createTree(ElemType root, BiTree lleaf, BiTree mleaf, BiTree rleaf)
{

     BiTree T = (BiTree)malloc(sizeof(BiTNode));
     if (T != NULL) {
               T->data = root;
               T->lChild = lleaf;
               T->mChild = mleaf;
               T->rChild = rleaf;
     }
     else exit(-1);
     return T;
}

//后序遍历
void TraverseBiTree(BiTree T)
{
     if (T == NULL) return ;
     TraverseBiTree(T->lChild);
     TraverseBiTree(T->mChild);
     TraverseBiTree(T->rChild);
     if(T->data != " ") printf("%s ", T->data);
}


    LinkedList list = NULL;
    LinkedList head = NULL;
    BiTree T, TL, TM, TR;
    
%}

%token END
%token NUM
%token ADD
%token MUL
%token MINUS
%token DIV
%% /* Grammar rules and actions follow.  */
input:
  /* empty */ 
| input line 
;
line:
  '\n'          { }
| exp END      { head = list->next;
                  T = head->data;
                  printf("Traverse BiTree:\n");
                  TraverseBiTree(T); 
				  printf("\n");
				  printf ("answer:%d\n", $1);}
;
exp:
  term           { $$ = $1;   printf("E->T\n");  
                  head = list->next;
                  TL = head->data;
                  TM = createLeaf(" ");
                  TR = createLeaf(" ");
                  T = createTree("E", TL, TM, TR);
                  list->next = head->next;
                  LinkedListInsert(list, T);   }   
| exp ADD term   { $$ = $1 + $3; printf("E->E+T\n");  
                  head = list->next;
                  TL = (head->next)->data;
                  TM = createLeaf("+");
                  TR = head->data;
                  T = createTree("E", TL, TM, TR);
                  list->next = (head->next)->next;
                  LinkedListInsert(list, T);    } 
| exp MINUS term { $$ = $1 - $3; printf("E->E-T\n");  
                  head = list->next;
                  TL = (head->next)->data;
                  TM = createLeaf("+");
                  TR = head->data;
                  T = createTree("E", TL, TM, TR);
                  list->next = (head->next)->next;
                  LinkedListInsert(list, T); }				  
;
term:
  factor          { head = list->next; printf("T->F\n"); 
                    TL = head->data;
                    TM = createLeaf(" ");
                    TR = createLeaf(" ");
                    T = createTree("T", TL, TM, TR);
                    list->next = head->next;
                    LinkedListInsert(list, T);}
| term MUL factor { $$ = $1 * $3; printf("T->T*F\n"); 
                    head = list->next;
                    TL = (head->next)->data;
                    TM = createLeaf("*");
                    TR = head->data;
                    T = createTree("T", TL, TM, TR);
                    list->next = (head->next)->next;
                    LinkedListInsert(list, T);    } 
| term DIV factor { $$ = $1 / $3; printf("T->T/F\n"); 
                    head = list->next;
                    TL = (head->next)->data;
                    TM = createLeaf("/");
                    TR = head->data;
                    T = createTree("T", TL, TM, TR);
                    list->next = (head->next)->next;
                    LinkedListInsert(list, T);    
}
;
factor:
  '('exp')'
| NUM             {
					printf("F->%d\n", $1);
					int num = $1;
					int len = 0;
					char* temp1 = (char*)malloc(sizeof(char)*10);//c语言中指针,数组等必须要赋给空间
					char* temp2 = (char*)malloc(sizeof(char)*10);
					while(num)
					{
						temp1[len] = '0'+num%10;
						num /= 10;
						len++;
					}
					for(i = 0; i < len; ++i)
					{
						temp2[i] = temp1[len-i-1];
					}
					temp2[len] = '\0';
                    TL = createLeaf(temp2);
                    TM = createLeaf(" ");
                    TR = createLeaf(" ");
                    T = createTree("F", TL, TM, TR);
                    LinkedListInsert(list, T);}
;
%%
int
main(void)
{
  list = LinkedListInit();
  T = NULL, TL = NULL, TM = NULL, TR = NULL;
  /*yydebug = 1;*/    /*bison -d -t*/ /*bison -d -v*/
  yyparse();
  return 0;
}

/* Called by yyparse on error.  */
void
yyerror (char const *s)
{
  fprintf (stderr, "%s\n", s);
}

 

实验步骤


step1. run "bison -d trans.y"  //generate 2 files: trans.tab.c and trans.tab.h
step2. "trans.tab.h" adds into lex.l's package
           run "lex lex.l"    //generate 1 files: lex.yy.c
step3. together 3 files
           run "tcc trans.tab.c"  //generate 1 files: trans.tab.exe
step4. run "trans.tab

 

实验总结知识:

1:C语言中指针,数组等必须给空间,否则容易造成多个指针指向同一个位置 

     malloc用法

          char* temp = (char*)malloc(sizeof(temp)*10)   等价于申明了空间    char temp[10]

          char** temp = (char**)malloc(sizeof(temp*)*10) 等价于神明了空间  char* temp[10]

 

2:当你创建char temp[10]并在其中赋值后,务必要在最后添加'\0'

 

3:环境搭建:当你要在dos中直接运用bison -d trans.y ,须先将bison.exe添加到环境变量path中

             方法:在path最后添加 ; 以及exe所在路径

 

4:问题:构造语法树的方法?还有没有别的方法了 

 

5:当从输入流中想查看下一个字符,但是并不想读出它时

     c++  : char c = cin.peek();

     c      : char c = getc(stdin);

                  ungetc(c, stdin);

   用处 :从输入流123+456 想要分离出123 , + , 456 ,当每次用getchar()时,想要判断123是否结束,就需要getchar下一位

              一旦getchar下一位了,就把“+”号“吃”掉了,用peek来判断下一位是否是数字

你可能感兴趣的:(编译原理)