编译原理实验 之 Tiny C语言编译程序实验 语法分析

文章目录

首先回顾项目架构

复制代码
-MAIN.C  主程序
-GLOBALS.H  全局类型及变量(如Token类属及语法树结点的组成)
-UTIL.H、UTIL.C  各步骤的实用函数。如输出Token,生成语法树结点等
-SCAN.C、SCAN.H  词法分析程序及其头文件
-PARSE.C、PARSE.H  语法分析程序及其头文件
-ANALYZE.C、ANALYZE.H  语义检查程序及其头文件
-SYMTAB.C、SYMTAB.H  符号表生成程序及其头文件
-CGEN.H、CGEN.C、CODE.C、CODE.H  目标代码生成程序及其头文件
-TM  编译sample.tny源程序后得到目标代码,在该虚拟机上运行得到结果

明确任务

  • 本次实现完成的是语法分析
  • parse.c文件
c 复制代码
typedef enum {StmtK,ExpK} NodeKind;
typedef enum {IfK,RepeatK,AssignK,ReadK,WriteK} StmtKind;
typedef enum {OpK,ConstK,IdK} ExpKind;

typedef enum {Void,Integer,Boolean} ExpType;

#define MAXCHILDREN 3

typedef struct treeNode
   { struct treeNode * child[MAXCHILDREN];
     struct treeNode * sibling;
     int lineno;
     NodeKind nodekind;
     union { StmtKind stmt; ExpKind exp;} kind;
     union { TokenType op;
            int val;
            char * name; } attr;
     ExpType type; 
   } TreeNode;

/****************************************************/
/* File: parse.c                                        */
/* The parser implementation for the TINY compiler          */
/****************************************************/

#include "globals.h"
#include "util.h"
#include "scan.h"
#include "parse.h"

static TokenType token; /* holds current token */

/* function prototypes for recursive calls */
static TreeNode * stmt_sequence(void);
static TreeNode * statement(void);
static TreeNode * if_stmt(void);
static TreeNode * repeat_stmt(void);
static TreeNode * assign_stmt(void);
static TreeNode * read_stmt(void);
static TreeNode * write_stmt(void);
static TreeNode * exp(void);
static TreeNode * simple_exp(void);
static TreeNode * term(void);
static TreeNode * factor(void);

static void syntaxError(char * message)
{ fprintf(listing,"\n>>> ");
  fprintf(listing,"Syntax error at line %d: %s",lineno,message);
  Error = TRUE;
}

static void match(TokenType expected)
{ if (token == expected) token = getToken();
  else {
    syntaxError("unexpected token -> ");
    printToken(token,tokenString);
    fprintf(listing,"      ");
  }
}

TreeNode * stmt_sequence(void)
{ TreeNode * t = statement();
  TreeNode * p = t;
  while ((token!=ENDFILE) && (token!=END) &&
         (token!=ELSE) && (token!=UNTIL))
  { TreeNode * q;
    match(SEMI);
    q = statement();
    if (q!=NULL) {
      if (t==NULL) t = p = q;
      else /* now p cannot be NULL either */
      { p->sibling = q;
        p = q;
      }
    }
  }
  return t;
}

TreeNode * statement(void)
{ TreeNode * t = NULL;
  switch (token) {
    case IF : t = if_stmt(); break;
    case REPEAT : t = repeat_stmt(); break;
    case ID : t = assign_stmt(); break;
    case READ : t = read_stmt(); break;
    case WRITE : t = write_stmt(); break;
    default : syntaxError("unexpected token -> ");
              printToken(token,tokenString);
              token = getToken();
              break;
  } /* end case */
  return t;
}

TreeNode * if_stmt(void)
{          
   ......          //此处请自己填写
}

TreeNode * repeat_stmt(void)
{
   ......          //此处请自己填写
}

TreeNode * assign_stmt(void)
{ 
   ......          //此处请自己填写
}

TreeNode * read_stmt(void)
{
   ......          //此处请自己填写
}

TreeNode * write_stmt(void)
{
   ......          //此处请自己填写
}

TreeNode * exp(void)
{ TreeNode * t = simple_exp();
  if ((token==LT)||(token==EQ)) {
    TreeNode * p = newExpNode(OpK);
    if (p!=NULL) {
      p->child[0] = t;
      p->attr.op = token;
      t = p;
    }
    match(token);
    if (t!=NULL)
      t->child[1] = simple_exp();
  }
  return t;
}

TreeNode * simple_exp(void)
{
   ......          //此处请自己填写
}

TreeNode * term(void)
{
   ......          //此处请自己填写
}

TreeNode * factor(void)
{
   ......          //此处请自己填写
}

/****************************************/
/* the primary function of the parser   */
/****************************************/
/* Function parse returns the newly 
 * constructed syntax tree
 */
TreeNode * parse(void)
{ TreeNode * t;
  token = getToken();
  t = stmt_sequence();
  if (token!=ENDFILE)
    syntaxError("Code ends before file\n");
  return t;
}

具体的实现

  • 完善这个parse.c文件:直接把parse.c和要求丢给ai即可

    要求:填写各语法符号的递归下降子程序,完成语法分析器parse.c。
    约定:
    -用递归下降分析法,为每个语法符号编写子程序。进入每个子程序前已读入一个新Token。
    -一个语法结构的内部表示形式为语法树,数据结构是globals.h中的treeNode。在做语法分析的同时建立语法结构的内部表示------语法树。

  • 生成完成之后,修改main.c中的参数设置

c 复制代码
/* set NO_PARSE to TRUE to get a scanner-only compiler */
#define NO_PARSE FALSE
/* set NO_ANALYZE to TRUE to get a parser-only compiler */
#define NO_ANALYZE TRUE

/* set NO_CODE to TRUE to get a compiler that does not
 * generate code
 */
#define NO_CODE TRUE
  • 还有下面的参数
c 复制代码
/* allocate and set tracing flags */
int EchoSource = FALSE;
int TraceScan = FALSE;
int TraceParse = TRUE;
int TraceAnalyze = FALSE;
int TraceCode = FALSE;
int Error = FALSE;
  • 接着就可以测试语法分析,xxxxx替换为编译之后的文件名,自己取
bash 复制代码
gcc main.c util.c scan.c parse.c -o xxxxx
  • 测试,xxxxx是上面编译之后的程序,SAMPLE.TNY是文件夹里面本身就有的测试文件
bash 复制代码
./xxxxx SAMPLE.TNY 

结果图

相关推荐
444A4E15 天前
C++多态完全指南:从虚函数到底层虚表机制,一文彻底掌握
c++·编译原理
脏脏a23 天前
程序环境和预处理
c语言·编译原理
l1n3x23 天前
编译原理前端-词法分析
算法·编译原理
G皮T23 天前
【Python Cookbook】字符串和文本(五):递归下降分析器
数据结构·python·正则表达式·字符串·编译原理·词法分析·语法解析
444A4E1 个月前
C++模板:泛型编程的魔法手册,从入门到“魔改”
c++·编译原理
梁辰兴1 个月前
编译原理——词法分析
计算机·it·编译原理·计算机基础
黎明blooms3 个月前
编译原理之基于自动机的词法分析器的设计与实现
c++·算法·编译原理
胡译胡说4 个月前
日本中学生创造了一门“类似中文”的编程语言
c++·编译原理
极客代码4 个月前
深入理解C语言:编译原理
c语言·开发语言·性能优化·编译原理·代码优化