精华内容
下载资源
问答
  • TINY编译器

    2017-12-05 15:57:40
    TINY编译器,编译器是将一种语言翻译成还有一种语言的程序。编译器将源程序的代码作为输出,从而产生用目标语言编写的等价程序。比如源码为C/C++等高级语言,那么目标语言就是目标机器的机器代码。也就是能够直接...
  • Tiny编译器

    2015-12-29 20:21:53
    一款十分简单的编译器,适合学习汇编原理编译原理基础的新手学习,可以在次基础上设计自己的高级语言。
  • Tiny编译器源码

    2018-06-08 15:29:53
    tiny编译器源码,编译原理课程实验所用,为书籍配套的源码,可以在此代码基础上实现C-词法扫描,语法分析等
  • Tiny编译器+语言

    2009-04-15 11:05:21
    Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言Tiny编译器+语言
  • tiny编译器源码

    2014-11-07 10:21:50
    tiny编译器源码,希望可以帮助道大家学习编译器
  • Tiny编译器的源代码

    2014-12-29 10:42:01
    一共有两个Tiny编译器的源代码,供参考~实现TINY+编译器的词法分析和词义分析,以及建立语法树和语义分析。 包括源代码、可执行文件、详细设计报告
  • tiny 编译器 源码

    2009-11-16 23:31:38
    编译原理与实践书上tiny编译器的源码,初学习编译原理用。。。。
  • 完整的Tiny编译器

    2011-04-25 00:13:40
    Tiny编译器是《编译原理与实践》课上提供给同学的一个小型编译器案例,从过学习它并在此基础上修改它得到自己的编译器
  • TINY 编译器源代码

    2010-10-25 01:40:23
    c语言实现的TINY编译器源代码 输入文件即可生成机器码 对应教材《编译原理与实践》
  • Tiny编译器的实现,在其基础上做的实验,编译原理的实验利器
  • 扩张的tiny 编译器

    2009-06-14 16:07:26
    tiny编译器的基础上添加上一些新的功能,具体看源程序。
  • 《编译原理及实践》附录B中Tiny编译器源码 本书英文名:Compiler Construction: Principles and Practice
  • 我们需要熟悉TINY编译器的源代码,并根据编译过程的七个步骤,弄清楚TINY编译器源代码中每个函数的功能,重点是找出词法分析部分的源代码。用C语言开发工具Visual Studio,把TINY编译器的源代码文件编译成可执行文件...

    一、实验任务

    本部分取自编译原理实验一:词法分析器生成工具FLEX在TINY语言上的应用。

    我们知道,TINY是一门高级程序语言。TINY有它的词法规则和语法规则。TINY既然是一门高级程序语言,就要有TINY语言的编译器。TINY语言的编译器叫TINY编译器。

    我们需要熟悉TINY编译器的源代码,并根据编译过程的七个步骤,弄清楚TINY编译器源代码中每个函数的功能,重点是找出词法分析部分的源代码。用C语言开发工具Visual Studio,把TINY编译器的源代码文件编译成可执行文件TINY.exe。然后用TINY.exe编译一个用TINY语言写的源程序(放在sample.tny文件中)。TINY.exe会生成sample.tm文件,这个就是编译后的目标文件(可执行文件)。再用TM.exe这个虚拟机来运行sample.tm文件,得到sample.tm文件的运行结果。

    在这一部分,我们介绍如何在Visual Studio中编译运行TINY编译器源代码。这是后续实验的基础。

    二、实验环境

    Windows 10

    三、实验步骤

    1. 观察到实验压缩包中提供两个执行文件,但无法运行,这是由运行环境不兼容导致的。删掉这两个文件,在后面自己生成。

    在这里插入图片描述

    1. 在Visual Studio(已配置C++编译环境)中新建一个“Win32 控制台应用程序”,并将其命名为“TINY”,点击“确定”。

    在这里插入图片描述

    1. VS(Visual Studio的缩写,下同)将显示Win32应用程序向导。因为我们需要导入TINY编译器的.c文件与.h头文件,因此在这里选择“空项目”。

    在这里插入图片描述

    1. 选择【项目】-【添加现有项】,将TINY编译器的.c文件与.h头文件导入。即loucomp文件夹下除TM.c以外的全部.c文件与.h头文件

    在这里插入图片描述

    1. 可以观察到这些文件已经成功导入到TINY项目中。

    在这里插入图片描述

    1. 运行该项目,观察到C4996报错。

    在这里插入图片描述

    ERROR C4996:‘strcpy’: This function or variable may be unsafe. Consider using strcpt_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

    查阅相关资料,这是由于C语言不同版本函数用法不一致导致的。为解决该问题,选择【项目】-【属性】,在高级设置中的“禁用特定警告”一栏中填入4996。

    在这里插入图片描述

    1. 再次运行项目文件,生成TINY.exe成功。

    在这里插入图片描述

    1. VS默认将exe文件存储在项目目录下的debug文件夹下,如下图。

    在这里插入图片描述

    1. 使用同样的方法,在VS中创建一个名为TM的项目,导入TM.c文件,运行生成TM.exe可执行文件。TM.exe可以作为.tm文件的虚拟机,解释执行得到.tm文件的运行结果。
      在这里插入图片描述

    2. 完成!

    展开全文
  • tiny语言编译器源码,为新手学习编译原理提供很大帮助,包括tiny语言编译器和解释器,还有使用说明。
  • TINY编译器C++版

    2007-07-01 11:09:05
    我的编译原理课程设计,一个老外写的TINY编译器的C版,老师让我们改为C++版的。
  • 1.生成TINY编译器 2.生成TM虚拟机 3.通过条件编译生成部分编译器 4.使用flex生成TINY编译器 5.使用bison生成TINY编译器 实验环境 按照老师的要求,以及课程中心提供的所有环境资料,这个实验本应在win下运行...

    实验一 / 第一部分

    实验内容:

    1.生成TINY编译器
    2.生成TM虚拟机
    3.通过条件编译生成部分编译器
    4.使用flex生成TINY编译器
    5.使用bison生成TINY编译器


    实验环境

    按照老师的要求,以及课程中心提供的所有环境资料,这个实验本应在win下运行,搭配VC++。Linux用户只能自己手写Makefile,强迁Linux生产环境。好在搜寻了近一天找到了这个实验的所有源代码,我又快乐了!这个实验,我结合了自己的一些理解,写了几个Makefile,希望能够给大家带来启发。

    在这里插入图片描述

    • 操作系统:Linux
    • 操作软件:VsCode

    资源

    • Tiny源代码:bigconvience
    • 参考书籍:《编译原理及实践》

    源码部署

    源码,一定一定要从GitHub上拿,不是质量问题,是环境适配问题,一般网上的都是win的源码,强改Makefile适配Linux 代价巨大,建议绕行(下面也有windows源码改Linux的教程)。

    • 下载源码
    $ git clone https://github.com/bigconvience/BooksCode
    
    • 拿到loucomp_linux之后,要修改makefile,让他更加适合本实验,修改如下,新增了 -w选项屏蔽警告,make cifa选项条件编译。
    #
    # Makefile for TINY
    # Gnu C Version
    # K. Louden 2/3/98
    # updated by qdl in 2020/10/30
    # 
    
    CC = gcc
    
    CFLAGS = -w
    
    OBJS = main.o util.o scan.o parse.o symtab.o analyze.o code.o cgen.o
    
    all: tiny tm
    
    tiny: $(OBJS)
    	$(CC) $(CFLAGS) $(OBJS) -o tiny
    
    tm: tm.c
    	$(CC) $(CFLAGS) tm.c -o tm
    
    cifa: cifaMain.o util.o scan.o
    	$(CC) $(CFLAGS) -o $@ cifaMain.o util.o scan.o
    
    cifaMain.o: cifaMain.c globals.h
    	$(CC) $(CFLAGS) -c cifaMain.c
    
    main.o: main.c globals.h util.h scan.h parse.h analyze.h cgen.h
    	$(CC) $(CFLAGS) -c main.c
    
    util.o: util.c util.h globals.h
    	$(CC) $(CFLAGS) -c util.c
    
    scan.o: scan.c scan.h util.h globals.h
    	$(CC) $(CFLAGS) -c scan.c
    
    parse.o: parse.c parse.h scan.h globals.h util.h
    	$(CC) $(CFLAGS) -c parse.c
    
    symtab.o: symtab.c symtab.h
    	$(CC) $(CFLAGS) -c symtab.c
    
    analyze.o: analyze.c globals.h symtab.h analyze.h
    	$(CC) $(CFLAGS) -c analyze.c
    
    code.o: code.c code.h globals.h
    	$(CC) $(CFLAGS) -c code.c
    
    cgen.o: cgen.c globals.h symtab.h code.h cgen.h
    	$(CC) $(CFLAGS) -c cgen.c
    
    clean:
    	-rm tiny
    	-rm tm
    	-rm $(OBJS)
    	-rm cifaMain.o
    	-rm cifa
    

    for Linux环境就搭建好了,只要两个步骤即可。

    解决for windows的tiny源码适配Linux问题,网上拿到的源码大多是在windows环境下运行的,如果你不是使用的git仓库中的代码loucomp_linux,那么接下来的操作或许对你有用。
    看了看makefile文件,-del,一个标准的windwos-shell,要适配linux则应该修改Makefile;除此之外,还有文件命名问题,目录中所有文件都是大写,但是引入头文件却是小写,因此要修改文件命名;为使这个TINY源代码适应Linux,主要有两步:

    • 修改文件名:

    在网上看到的一条脚本,可以将目录下所有的文件命名为小写。(建议文件夹不要修改)

    for i in *
    do
      mv $i `ls $i | tr [A-Z] [a-z]`
    done
    
    • 修改Makefile:
    #
    # Makefile for TINY
    # Gnu C Version
    # K. Louden 2/3/98
    # updated by qdl in 2020/10/30
    # 
    
    CC = gcc
    
    CFLAGS = -w
    
    OBJS = main.o util.o scan.o parse.o symtab.o analyze.o code.o cgen.o
    
    all: tiny tm
    
    tiny: $(OBJS)
    	$(CC) $(CFLAGS) $(OBJS) -o tiny
    
    tm: tm.c
    	$(CC) $(CFLAGS) tm.c -o tm
    
    cifa: cifaMain.o util.o scan.o
    	$(CC) $(CFLAGS) -o $@ cifaMain.o util.o scan.o
    
    cifaMain.o: cifaMain.c globals.h
    	$(CC) $(CFLAGS) -c cifaMain.c
    
    main.o: main.c globals.h util.h scan.h parse.h analyze.h cgen.h
    	$(CC) $(CFLAGS) -c main.c
    
    util.o: util.c util.h globals.h
    	$(CC) $(CFLAGS) -c util.c
    
    scan.o: scan.c scan.h util.h globals.h
    	$(CC) $(CFLAGS) -c scan.c
    
    parse.o: parse.c parse.h scan.h globals.h util.h
    	$(CC) $(CFLAGS) -c parse.c
    
    symtab.o: symtab.c symtab.h
    	$(CC) $(CFLAGS) -c symtab.c
    
    analyze.o: analyze.c globals.h symtab.h analyze.h
    	$(CC) $(CFLAGS) -c analyze.c
    
    code.o: code.c code.h globals.h
    	$(CC) $(CFLAGS) -c code.c
    
    cgen.o: cgen.c globals.h symtab.h code.h cgen.h
    	$(CC) $(CFLAGS) -c cgen.c
    
    clean:
    	-rm tiny
    	-rm tm
    	-rm $(OBJS)
    	-rm cifaMain.o
    	-rm cifa
    

    至此环境搭建成功

    实验步骤

    • makefile编译程序
    $ make
    

    1.生成TINY编译器

    $ ./tiny sample.tny
    
    • 结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mKhmBIb9-1604074472122)(/home/qdl/Documents/Subject/大三/编译原理/实验/1/README.assets/image-20201030183704594.png)]

    2.生成TM虚拟机

    $ ./tm sample.tm
    TM  simulation (enter h for help)...
    Enter command: g
    Enter value for IN instruction: 7
    OUT instruction prints: 5040
    HALT: 0,0,0
    Halted
    Enter command: q
    Simulation done.
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ogqoc6cR-1604074472126)(/home/qdl/Documents/Subject/大三/编译原理/实验/1/README.assets/image-20201030183741199.png)]

    3.通过条件编译生成部分编译器

    由于使用Linux环境,用Makefile可以完成部分编译器的编译,因此没必要用VC++,前提是合理的编写Makefile。

    • 新建文件cifaMain.c,内容由main.c拷贝。然后修改cifaMain.c
    修改cifaMain.c中条件编译标志和控制显示标志
    NO_PARSE:从FALSE改为TRUE
    EchoSource和TraceScan:从FALSE改为TRUE
    
    • Makefile增加两行(在开始的Makefile修改中已经完成):
    cifa: cifaMain.o util.o scan.o
    	$(CC) $(CFLAGS) -o $@ cifaMain.o util.o scan.o
    
    cifaMain.o: cifaMain.c globals.h util.h scan.h
    	$(CC) $(CFLAGS) -c cifaMain.c
    
    • 使用make cifa进行部分编译
    $ make cifa
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6NflcBY2-1604074472128)(/home/qdl/Documents/Subject/大三/编译原理/实验/1/README.assets/image-20201030183835298.png)]

    • 测试cifa:
    $ ./cifa sample.tny
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-buMw9Gw2-1604074472131)(/home/qdl/Documents/Subject/大三/编译原理/实验/1/README.assets/image-20201030172316312.png)]

    4.使用flex生成TINY编译器

    • 安装flex
    $ sudo apt-get install flex
    $ flex --version
    flex 2.6.4
    
    • 在lex目录执行lex:
    $ cd  /lex
    $ flex tiny.l
    
    • 在lex目录创建项目依赖:
    $ cp ../main.c ../globals.h ../util.c ../util.h /scan.h ../sample.tny .
    
    • 修改main.c的编译条件:
    NO_PARSE:从FALSE改为TRUE
    EchoSource和TraceScan:从FALSE改为TRUE
    
    • 编写Makefile:
    $ touch Makefile
    
    #
    # Makefile for Lex
    # created by qdl in 2020/10/30
    #
    
    CC = gcc
    
    CFLAGS = -w
    
    OBJS = main.o util.o scan.o
    
    all: tiny
    
    tiny: main.o util.o scan.o
    	$(CC) $(CFLAGS) -o $@ main.o util.o scan.o -lfl
    
    main.o: main.c globals.h
    	$(CC) $(CFLAGS) -c main.c
    
    util.o: util.c util.h globals.h
    	$(CC) $(CFLAGS) -c util.c
    
    scan.o: lex.yy.c scan.h util.h globals.h
    	$(CC) $(CFLAGS) -c lex.yy.c -o scan.o
    
    clean:
    	-rm $(OBJS)
    	-rm tiny
    
    • 测试程序:
    $ ./tiny sample.tny
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6XWwC4Kr-1604074472133)(/home/qdl/Documents/Subject/大三/编译原理/实验/1/README.assets/image-20201030203202848.png)]

    5.使用bison生成TINY编译器

    • 安装bison
    $ sudo apt install bison
    $ bison --version
    bison (GNU Bison) 3.5.1
    
    • 生成语法分析程序
    $ bison -d tiny.y
    
    • 修改YACC目录中的那个Globals.h使其包含的y.tab.h改为生成的tiny.tab.h
    #include "y.tab.h"  ----> #include "tiny.tab.h" 	
    
    • 构建项目结构:
    $ cp ../main.c ../util.c ../util.h ../scan.h ../lex.yy.c ../parse.h ../sample.tny .
    
    • 修改main.c中的编译条件:
    NO_ANALYZE TRUE:从FALSE改为TRUE
    EchoSource和TraceScan:从FALSE改为TRUE
    
    • 编写Makefile:
    $ touch Makefile
    
    #
    # Makefile for yacc
    # created by qdl in 2020/10/30
    # 
    
    CC = gcc
    
    CFLAGS = -w
    
    OBJS = main.o util.o scan.o parse.o
    
    all: tiny
    
    tiny: $(OBJS)
    	$(CC) $(CFLAGS) $(OBJS) -o tiny -lfl
    
    
    main.o: main.c globals.h util.h scan.h parse.h
    	$(CC) $(CFLAGS) -c main.c
    
    util.o: util.c util.h globals.h
    	$(CC) $(CFLAGS) -c util.c
    
    scan.o: lex.yy.c scan.h util.h globals.h
    	$(CC) $(CFLAGS) -c lex.yy.c -o scan.o
    
    parse.o: tiny.tab.c parse.h scan.h globals.h util.h tiny.tab.h
    	$(CC) $(CFLAGS) -c tiny.tab.c -o parse.o
    
    clean:
    	-rm tiny
    	-rm $(OBJS)
    
    • 报错信息error: static declaration of ‘yylex’ follows non-static declaration
    未定义,因此要修改一下tiny.tab.c,在开头添加一句:static int yylex(void);
    
    • 验证:
    $ make 
    $ ./tiny sample.tny
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7FtVo4A-1604074472134)(/home/qdl/Documents/Subject/大三/编译原理/实验/1/README.assets/image-20201031000028392.png)]

    至此,实验结束,主要是工具Tiny编译器源码的熟悉,目录结构的了解以及对Tiny语言的初步学习。

    展开全文
  • Tiny编译器的 题目 分析 源程序 生成的exe文件 俱全
  • 编译原理及实践教材附带了TINY编译器,在这里对这个小型编译器的代码,做一下简单的解析.  TINY编译器的词法分析Lex源程序是: %{ #include "globals.h" #include "util.h" #include "scan.h" /* lexeme...

    编译原理及实践教材附带了TINY编译器,在这里对这个小型编译器的代码,做一下简单的解析.

       TINY编译器的词法分析Lex源程序是:

    %{

    #include "globals.h"

    #include "util.h"

    #include "scan.h"

    /* lexeme of identifier or reserved word */

    char tokenString[MAXTOKENLEN+1];

    %}

    digit       [0-9]

    number      {digit}+

    letter      [a-zA-Z]

    identifier  {letter}+

    newline     /n

    whitespace  [ /t]+

    %%

    "if"            {return IF;}

    "then"          {return THEN;}

    "else"          {return ELSE;}

    "end"           {return END;}

    "repeat"        {return REPEAT;}

    "until"         {return UNTIL;}

    "read"          {return READ;}

    "write"         {return WRITE;}

    ":="            {return ASSIGN;}

    "="             {return EQ;}

    "<"             {return LT;}

    "+"             {return PLUS;}

    "-"             {return MINUS;}

    "*"             {return TIMES;}

    "/"             {return OVER;}

    "("             {return LPAREN;}

    ")"             {return RPAREN;}

    ";"             {return SEMI;}

    {number}        {return NUM;}

    {identifier}    {return ID;}

    {newline}       {lineno++;}

    {whitespace}    {/* skip whitespace */}

    "{"             { char c;

                      do

                      { c = input();

                        if (c == EOF) break;

                        if (c == '/n') lineno++;

                      } while (c != '}');

                    }

    .               {return ERROR;}

    %%

    TokenType getToken(void)

    { static int firstTime = TRUE;

      TokenType currentToken;

      if (firstTime)

      { firstTime = FALSE;

        lineno++;

        yyin = source;

        yyout = listing;

      }

      currentToken = yylex();

      strncpy(tokenString,yytext,MAXTOKENLEN);

      if (TraceScan) {

        fprintf(listing,"/t%d: ",lineno);

        printToken(currentToken,tokenString);

      }

      return currentToken;

    }

    TINY编译器的语法分析Yacc源程序是:

    %{

    #define YYPARSER /* distinguishes Yacc output from other code files */

    #include "globals.h"

    #include "util.h"

    #include "scan.h"

    #include "parse.h"

    #define YYSTYPE TreeNode *

    static char * savedName; /* for use in assignments */

    static int savedLineNo;  /* ditto */

    static TreeNode * savedTree; /* stores syntax tree for later return */

    %}

    %token IF THEN ELSE END REPEAT UNTIL READ WRITE

    %token ID NUM

    %token ASSIGN EQ LT PLUS MINUS TIMES OVER LPAREN RPAREN SEMI

    %token ERROR

     

    %% /* Grammar for TINY */

    program     : stmt_seq

                     { savedTree = $1;}

                ;

    stmt_seq    : stmt_seq SEMI stmt

                     { YYSTYPE t = $1;

                       if (t != NULL)

                       { while (t->sibling != NULL)

                            t = t->sibling;

                         t->sibling = $3;

                         $$ = $1; }

                         else $$ = $3;

                     }

                | stmt  { $$ = $1; }

                ;

    stmt        : if_stmt { $$ = $1; }

                | repeat_stmt { $$ = $1; }

                | assign_stmt { $$ = $1; }

                | read_stmt { $$ = $1; }

                | write_stmt { $$ = $1; }

                | error  { $$ = NULL; }

                ;

    if_stmt     : IF exp THEN stmt_seq END

                     { $$ = newStmtNode(IfK);

                       $$->child[0] = $2;

                       $$->child[1] = $4;

                     }

                | IF exp THEN stmt_seq ELSE stmt_seq END

                     { $$ = newStmtNode(IfK);

                       $$->child[0] = $2;

                       $$->child[1] = $4;

                       $$->child[2] = $6;

                     }

                ;

    repeat_stmt : REPEAT stmt_seq UNTIL exp

                     { $$ = newStmtNode(RepeatK);

                       $$->child[0] = $2;

                       $$->child[1] = $4;

                     }

                ;

    assign_stmt : ID { savedName = copyString(tokenString);

                       savedLineNo = lineno; }

                  ASSIGN exp

                     { $$ = newStmtNode(AssignK);

                       $$->child[0] = $4;

                       $$->attr.name = savedName;

                       $$->lineno = savedLineNo;

                     }

                ;

    read_stmt   : READ ID

                     { $$ = newStmtNode(ReadK);

                       $$->attr.name =

                         copyString(tokenString);

                     }

                ;

    write_stmt  : WRITE exp

                     { $$ = newStmtNode(WriteK);

                       $$->child[0] = $2;

                     }

                ;

    exp         : simple_exp LT simple_exp

                     { $$ = newExpNode(OpK);

                       $$->child[0] = $1;

                       $$->child[1] = $3;

                       $$->attr.op = LT;

                     }

                | simple_exp EQ simple_exp

                     { $$ = newExpNode(OpK);

                       $$->child[0] = $1;

                       $$->child[1] = $3;

                       $$->attr.op = EQ;

                     }

                | simple_exp { $$ = $1; }

                ;

    simple_exp  : simple_exp PLUS term

                     { $$ = newExpNode(OpK);

                       $$->child[0] = $1;

                       $$->child[1] = $3;

                       $$->attr.op = PLUS;

                     }

                | simple_exp MINUS term

                     { $$ = newExpNode(OpK);

                       $$->child[0] = $1;

                       $$->child[1] = $3;

                       $$->attr.op = MINUS;

                     }

                | term { $$ = $1; }

                ;

    term        : term TIMES factor

                     { $$ = newExpNode(OpK);

                       $$->child[0] = $1;

                       $$->child[1] = $3;

                       $$->attr.op = TIMES;

                     }

                | term OVER factor

                     { $$ = newExpNode(OpK);

                       $$->child[0] = $1;

                       $$->child[1] = $3;

                       $$->attr.op = OVER;

                     }

                | factor { $$ = $1; }

                ;

    factor      : LPAREN exp RPAREN

                     { $$ = $2; }

                | NUM

                     { $$ = newExpNode(ConstK);

                       $$->attr.val = atoi(tokenString);

                     }

                | ID { $$ = newExpNode(IdK);

                       $$->attr.name =

                             copyString(tokenString);

                     }

                | error { $$ = NULL; }

                ;

     

    %%

    int yyerror(char * message)

    { fprintf(listing,"Syntax error at line %d: %s/n",lineno,message);

      fprintf(listing,"Current token: ");

      printToken(yychar,tokenString);

      Error = TRUE;

      return 0;

    }

     

    所用到的代码示例的输入文件SAMPLE.TNY:

    { Sample program

      in TINY language -

      computes factorial

    }

    read x; { input an integer }

    if 0 < x then { don't compute if x <= 0 }

      fact := 1;

      repeat

        fact := fact * x;

        x := x - 1

      until x = 0;

      write fact  { output factorial of x }

    end

    附带的代码示例手工书写了词法分析,语法分析,我们在这里一步步对代码做简单的解析.

    词法分析:

    词法编译是编译的基础,主要任务是从左至右逐个字符地对源程序进行扫描,产生一个单词记号(token).每个单词记号都是由词法分析程序从剩余的输入字符串的开头识别出的某种字符串格式,把作为字符串输入的源程序改造成单词符号串的中间形式.

    单词的类型:

    根据单词在语言中的作用将单词大致分为五类:

    (1).关键字:这类单词在特定语言中有固定的意义;

    (2).标志符:标志符的作用是为某个实体命名,以便于程序引用,可以用标志符来命名的实体包括变量,过程,类,对象等;

    (3).常数:常数一般有整形,实型,布尔型,字符型等.

    (4).运算符:分为算术运算符,布尔运算符,关系运算符;

    (5).界符:类似于语言中的标的符号.

    单词的类别码:

    词法分析程序的输入是源程序字符串,输出是与源程序等价的符号序

    列.这些符号序列可以是如下的形式:

    (类别码,单词的值)

    其中类别码表示单词的种类,通常用整数表示.

    现在进入到词法分析的源程序,首先看一下GLOBALS.H的头文件:

    /*定义单词种类*/

    typedef enum {

        ENDFILE,ERROR,

        IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,

        ID,NUM,

        ASSIGN,EQ,LT,PLUS,MINUS,TIMES,OVER,LPAREN,RPAREN,SEMI

    } TokenType;

    /*定义结点类型:是语句结点还是表达式结点*/

    typedef enum {StmtK,ExpK} NodeKind;

    /*定义语句类别:if,repeat,assign,read,write语句*/

    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;

         然后在看一下词法扫描程序: SCAN.C

    SCAN.C

    /*定义的状态*/

    typedef enum

    {

        START,   /*初始状态*/

        INASSIGN,  /*进入到赋值状态*/

        INCOMMENT, /*进入到注释状态*/

        INNUM,     /*进入到数字状态*/

        INID,      /*进入到标志符状态*/

        DONE       /*状态结束*/

    }StateType;

    /*每当语法分析程序需要一个单词时,就调用该子程序,得到 (类别码,单词的值)*/

    TokenType getToken(void)

    int tokenStringIndex = 0;

        TokenType currentToken;

        StateType state = START;

        int save;

        while (state != DONE)

        {

            int c = getNextChar(); /*从输入buf中读入一个字符*/

            save = TRUE;

            switch (state)

            {

            case START:

                if (isdigit(c))

                    state = INNUM;

                else if (isalpha(c))  /*判断字母*/

                    state = INID;

                else if (c == ':')

                    state = INASSIGN;

                else if ((c == ' ') || (c == '/t') || (c == '/n'))

                    save = FALSE;

                else if (c == '{')

                {

                    save = FALSE;

                    state = INCOMMENT;

                }

                else

                {

                    state = DONE;

                    switch (c)

                    {

                    case EOF:

                        save = FALSE;

                        currentToken = ENDFILE;

                        break;

                    case '=':

                        currentToken = EQ;

                        break;

                    case '<':

                        currentToken = LT;

                        break;

                    case '+':

                        currentToken = PLUS;

                        break;

                    case '-':

                        currentToken = MINUS;

                        break;

                    case '*':

                        currentToken = TIMES;

                        break;

                    case '/':

                        currentToken = OVER;

                        break;

                    case '(':

                        currentToken = LPAREN;

                        break;

                    case ')':

                        currentToken = RPAREN;

                        break;

                    case ';':

                        currentToken = SEMI;

                        break;

                    default:

                        currentToken = ERROR;

                        break;

                    }

                }

                break;

            case INCOMMENT:

                save = FALSE;

                if (c == EOF)

                {

                    state = DONE;

                    currentToken = ENDFILE;

                }

                else if (c == '}') state = START;

                break;

            case INASSIGN:

                state = DONE;

                if (c == '=')

                    currentToken = ASSIGN;

                else

                {

                    /* backup in the input */

                    ungetNextChar();

                    save = FALSE;

                    currentToken = ERROR;

                }

                break;

            case INNUM:

                if (!isdigit(c))

                {

                    /* backup in the input */

                    ungetNextChar();

                    save = FALSE;

                    state = DONE;

                    currentToken = NUM;

                }

                break;

            case INID:

                if (!isalpha(c))

                {

                    /* backup in the input */

                    ungetNextChar();

                    save = FALSE;

                    state = DONE;

                    currentToken = ID;

                }

                break;

            case DONE:

            default/* should never happen */

                fprintf(listing,"Scanner Bug: state= %d/n",state);

                state = DONE;

                currentToken = ERROR;

                break;

            }

            if ((save) && (tokenStringIndex <= MAXTOKENLEN))

            {

                tokenString[tokenStringIndex++] = (char) c;

            }

            /*解析单词结束*/

            if (state == DONE)

            {

                tokenString[tokenStringIndex] = '/0';

                if (currentToken == ID)

                {

                    currentToken = reservedLookup(tokenString);

                }

            }

        }

        if (TraceScan)

        {

            fprintf(listing,"/t%d: ",lineno);

            printToken(currentToken,tokenString);

        }

        return currentToken;

    }

         在来看语法分析程序PARSE.C,主要的作用是形成一颗语法树:

    static TokenType token; /* 全局变量 */

    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

                {

                    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)

    {

        //对文法:IF exp THEN stmt_seq END

        //IF exp THEN stmt_seq ELSE stmt_seq END

        //的处理

        TreeNode * t = newStmtNode(IfK);

        match(IF);

        if (t!=NULL) t->child[0] = exp();

        match(THEN);

        if (t!=NULL) t->child[1] = stmt_sequence();

        if (token==ELSE)

        {

            match(ELSE);

            if (t!=NULL) t->child[2] = stmt_sequence();

        }

        match(END);

        return t;

    }

    TreeNode * repeat_stmt(void)

    {

        //对文法:REPEAT stmt_seq UNTIL exp

        //的处理

        TreeNode * t = newStmtNode(RepeatK);

        match(REPEAT);

        if (t!=NULL) t->child[0] = stmt_sequence();

        match(UNTIL);

        if (t!=NULL) t->child[1] = exp();

        return t;

    }

    TreeNode * assign_stmt(void)

    {

        //对赋值语句的处理

        //文法:ID ASSIGN exp

        TreeNode * t = newStmtNode(AssignK);

        if ((t!=NULL) && (token==ID))

        {

            t->attr.name = copyString(tokenString);

        }

        match(ID);

        match(ASSIGN);

        if (t!=NULL) t->child[0] = exp();

        return t;

    }

    TreeNode * read_stmt(void)

    {

        //对文法: READ ID

        //的处理

        TreeNode * t = newStmtNode(ReadK);

        match(READ);

        if ((t!=NULL) && (token==ID))

            t->attr.name = copyString(tokenString);

        match(ID);

        return t;

    }

    TreeNode * write_stmt(void)

    {

        //对文法: WRITE exp

        //的处理

        TreeNode * t = newStmtNode(WriteK);

        match(WRITE);

        if (t!=NULL) t->child[0] = exp();

        return t;

    }

    TreeNode * exp(void)

    {

        //对文法:exp: simple_exp LT simple_exp

        //          | simple_exp EQ simple_exp

        //          | simple_exp

        //的处理

        //先生成了左边的子表达式

        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;               //t是需要返回的

            }

            match(token);

            if (t!=NULL)

            {

                t->child[1] = simple_exp(); //在生成右边的子表达式

            }

        }

        return t;

    }

    TreeNode * simple_exp(void)

    {

        //对文法:simple_exp  : simple_exp PLUS term

        //                   | simple_exp MINUS term

        //                   | term

        //的处理

        //先生成term

        TreeNode * t = term();

        while ((token==PLUS)||(token==MINUS))

        {

            TreeNode * p = newExpNode(OpK);  //同样是构造操作符表达式结点

            if (p!=NULL)

            {

                p->child[0] = t;

                p->attr.op = token;

                t = p;

                match(token);

                t->child[1] = term();

            }

        }

        return t;

    }

    TreeNode * term(void)

    {

        //对文法: term   : term TIMES factor

        //               | term OVER factor

        //               | factor

        //的处理

        TreeNode * t = factor();

        while ((token==TIMES)||(token==OVER))

        {

            TreeNode * p = newExpNode(OpK);  //同样的处理方法

            if (p!=NULL)

            {

                p->child[0] = t;

                p->attr.op = token;

                t = p;

                match(token);

                p->child[1] = factor();

            }

        }

        return t;

    }

    TreeNode * factor(void)

    {

        //对文法: factor : LPAREN exp RPAREN

        //               | NUM

        //               | ID

        //的处理

        //判断单词的类型

        TreeNode * t = NULL;

        switch (token)

        {

        case NUM :

            t = newExpNode(ConstK); 

            if ((t!=NULL) && (token==NUM))

                t->attr.val = atoi(tokenString);

            match(NUM);

            break;

        case ID :

            t = newExpNode(IdK);     

            if ((t!=NULL) && (token==ID))

                t->attr.name = copyString(tokenString);

            match(ID);

            break;

        case LPAREN :

            match(LPAREN);

            t = exp();

            match(RPAREN);

            break;

        default:

            syntaxError("unexpected token -> ");

            printToken(token,tokenString);

            token = getToken();

            break;

        }

        return t;

    }

    TreeNode * parse(void)

    {

        TreeNode * t;

        token = getToken();

        t = stmt_sequence();

        if (token!=ENDFILE)

            syntaxError("Code ends before file/n");

        return t;

    }

         语法分析程序结束,形成一棵以第一条语句开始的参数语法树。

         下面在看一下主程序main()的调用:

    main( int argc, char * argv[] )

    { TreeNode * syntaxTree;

        char pgm[120]; /* source code file name */

        if (argc != 2){

            fprintf(stderr,"usage: %s <filename>/n",argv[0]);

            exit(1);

        }

        strcpy(pgm,argv[1]) ;

        if (strchr (pgm, '.') == NULL){

            strcat(pgm,".tny");

        }

        source = fopen(pgm,"r");

        if (source==NULL){

            fprintf(stderr,"File %s not found/n",pgm);

            exit(1);

        }

        listing = stdout;

        fprintf(listing,"/nTINY COMPILATION: %s/n",pgm);

        syntaxTree = parse();  /*调用PARSE.C里的子程序*/

        if (TraceParse) {

            fprintf(listing,"/nSyntax tree:/n");

            printTree(syntaxTree);

        }

    }

     

    展开全文
  • TINY编译器》源码在书上附录B,它并没有使用lex和

           工作环境:

               操作系统:  ubuntu 13.04;

                 IDE:code::block 12.11;

                词法分析程序生成器:lex

                语法分析程序生成器:yacc

          《TINY编译器》源码在书上附录B,它并没有使用lex和yacc生成词法/语法扫描程序,而是自己编写了scan.c和parse.c,用来实现词法扫描和语法扫描。我们的目标是利用lex和yacc生成词法与语法扫描程序,从而代替scan.c与parse.c,实现TINY编译器。

           大体工作,我分为五个部分:

                一:TINY源代码,不加任何修改,在ubuntu下编译、运行成功。

                二:单独使用lex,生成词法分析程序,替代san.c,在ubuntu下编译、运行成功

                三:单独使用yacc,生成语法分析程序,替代parse.c,在ubuntu下编译、运行成功

                四:lex和yacc配合使用,生成词法、语法分析程序,替代scan.c、parse.c,在ubuntu下编译、运行成功。

                五:进行适当的词法输入文件与语法输入文件的分析、修改,实现扩展的编译器。最高目标是实现自设计编译器。

     

          上一篇博客已经介绍了工作一的完成步骤,在此不再赘述。下面介绍工作二的完成。

           TINY编译器源代码中有一个LEX文件夹,里面放有TINY.L文件,此文件便是lex的输入文件,文件格式不再叙述。还有一个YACC文件夹,里面放有TINY.Y文件,此文件是yacc的输入文件。将这两个输入文件拷贝到其他源码存在的文件夹下,也就是其上一目录文件夹。

           刚开始,需要在TINY.L的最后添加一个yywrap()函数。添加内容为:

                 int yywrap()

                {

                      return 1;

                }

              

    yywrap() 这一函数在文件(或输入)的末尾调用。 如果函数的返回值是1,就停止解析。 因此它可以用来解析多个文件。 代码可以写在第三段,这就能够解析多个文件。 方法是使用 yyin 文件指针(见上表)指向不同的文件,直到所有的文件都被解析。 最后,yywrap() 可以返回 1 来表示解析的结束。

            首先,使用命令:yacc -d TINY.Y

           生成文件 y.tab.c和y.tab.h。一个是语法分析程序源码,另一个则是与之相关的头文件。在此工作二中,我们只需要.h头文件。

           然后使用命令: lex TINY.L

           生成文件lex.yy.c,这便是我们需要的词法分析源程序。


          文件已经全部准备好了,剩下的只需新建一个工程,将lex.yy.c、y.tab.h和其他源码文件(不包括scan.c)文件加入到同一个工程中即可。

          再次不再叙述工程建立。也可像上一个博客中提到的那样,写makefile文件,为减少工作量,我使用code::block IDE,用来编译工程。当然,上一博客中也可用IDE来编译工程,而无需makefile文件。

    展开全文
  • TINY编译器的词法分析程序在scan.c文件zhon
  • 同学们,我是在上编译原理课,老师布置的作业,自己改进了一个编译器。是用c语言实现的tiny编译器
  • 【编译原理】TINY编译器学习(一)

    千次阅读 2014-06-30 22:14:52
    《编译原理及实践》中附带的TINY编译器,代码仅有几千行, 这点代码就实现了一个完整的编译器,及对应的目标代码运行程序,接下来会用一段时间研究下这个代码。 1. 源代码来源 Google “loucomp” 下载即可。...
  • TINY编译器《编译原理》

    千次阅读 2016-03-17 21:37:49
    实现TINY+编译器 ,华南理工大学,《编译原理》课程实验
  • TINY是《编译原理与实践》一书中介绍的教学编程语言,该语言缺少真正程序设计语言的主要特征,但足以例证编译器的主要特征了。本文将介绍该编译器的实现过程,完整的实现代码loucomp_linux中,供编译原理初学者参考...
  • tiny编译器实验报告

    2008-07-16 15:43:54
    tiny的设计文档,水平可能一般般,高手就“砖”我吧,相信对初学应该还是有帮助的
  • 编译原理 Tiny编译器和TM虚拟机

    千次阅读 2019-10-24 09:14:06
    编译器的设计流程 词法分析 语法分析 语义分析 Lex & Yacc Lex 首先,lex和yacc是开源工具,帮助开发者实现语法,词法分析。如果作为一个开发者去使用它们,就需要阅读它们的说明书,直到你会用,一句话,就是...
  • 一个TINY编译器程序

    2009-02-13 10:13:56
    这是一个完整的编译器,用C语言实现了扫描,语法分析,语义分析,等功能。代码中实现了自底向上分析算法。是一个不错的编译器。供程序员参考。
  • 首先,在网上下载tiny编译器源码。  解压后,发现内部

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 637
精华内容 254
关键字:

tiny编译器