编译原理学习:TINY语言词法扫描程序实现

最近对解释型程序(类似python或者是linux里的bc计算器)非常感兴趣,就开始学习一下编译原理。今天自己实现了TINY语言的词法扫描程序。大部分参考《编译原理及实践》一书。但是我做了一些小小的改进。

先说一下TINY语言:

1、注释:放在一对大括号内。书上的注释不能嵌套,我做了一点改进,允许嵌套。

2、关键字:read write if end repeat until else

3、类型:只支持整型和布尔型。

4、计算:+ - * / ( ) < = :=,其中:=为赋值运算,=为判断。没有〈和<= >=

一个示例的TINY语言程序:

test.tine: (选自《编译原理及实践》)

{ 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

在globals.h中,涉及到一些类型的声明:

#ifndef GLOBALS_H
#define GLOBALS_H

#include <stdio.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;
extern lineno;

/* The max size of identifier of reserved word */
#define MAXTOKENLEN 50

#endif

用于生成词法扫描的flex输入,这是程序的核心部分:

tiny.l

%{
#include <stdio.h>
#include <string.h>
#include "globals.h"
#include "util.h"

char tokenString[MAXTOKENLEN + 1];
%}

digit		[0-9]
number		{digit}+
letter		[a-zA-Z]
identifier	{letter}[a-zA-Z0-9]*
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}	<span style="white-space:pre">	</span>{return ID;}
{newline}		{lineno++;}
{whitespace}	<span style="white-space:pre">	</span>{ /* Do nothing */ }
"{"			{ char c;
			  int count = 1;
			  do
			  {
				  c = input();
				  if (c == EOF) break;
				  else if (c == '\n') lineno++;
				  else if (c == '{') count++;
				  else if (c == '}') count--;
			  } while (count != 0);
			}
.			{return ERROR;}

%%

TokenType getToken(void)
{
	TokenType currentToken;
	currentToken = yylex();
	strncpy(tokenString, yytext, MAXTOKENLEN);
	printf("%d: ", lineno);
	printToken(currentToken, tokenString);

	return currentToken;
}

printToken函数在util.c中实现:

util.h:

#ifndef UTIL_H
#define UTIL_H

#include "globals.h"

void printToken(TokenType token, char* tokenString);

TokenType getToken(void);

#endif

util.c:

#include "util.h"
#include <stdio.h>
#include "globals.h"

void printToken(TokenType token, char* tokenString)
{
	switch(token)
	{
		case IF:
		case THEN:
		case ELSE:
		case END:
		case REPEAT:
		case UNTIL:
		case READ:
		case WRITE:
			printf("\treversed word: %s\n", tokenString);
			break;
		case ID:
			printf("\tidentifier: %s\n", tokenString);
			break;
		case NUM:
			printf("\tnumber: %s\n", tokenString);
			break;
		case ASSIGN:
		case EQ:
		case LT:
		case PLUS:
		case MINUS:
		case TIMES:
		case OVER:
		case LPAREN:
		case RPAREN:
		case SEMI:
			printf("\toperator: %s\n", tokenString);
	}
}

这就是所有的文件了!最后,是makefile文件:

scanner.exe: main.o lex.yy.o util.o
	gcc main.o lex.yy.o util.o -o scanner.exe -lfl
main.o: main.c globals.h util.h
	gcc main.c -c
util.o: util.c util.h globals.h
	gcc util.c -c
lex.yy.o: tiny.l
	flex tiny.l
	gcc lex.yy.c -c

于是,一个简单的词法扫描程序就完成了。

由于使用的是默认的输入,所以这个程序直接支持从键盘输入,运行效果如下:

当然,也可以使用重定向操作,使用效果如下:

时间: 2024-08-03 03:04:35

编译原理学习:TINY语言词法扫描程序实现的相关文章

编译原理:tiny语言

描述真实的编译器非常困难."真正的"编译器--也就是希望在每天编程中用到的--内容太复杂而且不易在本教材中掌握.另一方面,一种很小的语言(其列表包括1 0页左右的文本)的编译也不可能准确地描述出"真正的"编译器所需的所有特征. 为了解决上述问题,人们在(A N S I)C中为小型语言提供了完整的源代码,一旦能明白这种技术,就能够很容易地理解这种小型语言的编译器了.这种语言称作T I N Y,在每一章的示例中都会用到它,它的编译代码也很快会被提到.完整的编译代码汇集在

编译原理学习导论

编译原理学习导论 大学课程为什么要开设编译原理呢?这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,但是编译原理却一直作为大学本科的必修课程,同一时候也成为了研究生入学考试的必考内容.编译原理及技术从本质上来讲就是一个算法问题而已,当然因为这个问题十分复杂,其解决算法也相对复杂.我们学的数据结构与算法分析也是讲算法的,只是讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比較专注解决一种的算法了.在20世纪50年代,编译器的编写一直被觉得是十分困难的事情

编译原理学习笔记 -- 绪论1

1. 语言处理器 语言处理系统 _________ 经过预 _______ 源程序 --> |预处理器| --> 处理的 --> |编译器| --> 目标汇编程序 -------- 源程序 ------- _______ 可重定位的 ______________ --> |汇编器| --> 机器代码 --> |链接器/加载器| --> 目标机器代码 ------- -------------- ↑ 库文件/可重定位对象文件 预处理器:把源程序聚合在一起,并宏

编译原理学习

编译原理学习笔记---- 不确定有穷自动机(NFA) 一个不确定的有穷自动机T是一个五元组,M={K,∑,f,S,Z} ⒈K是一个有穷集他的每一个元素称作一个状态. ⒉∑是一个字母表,他的每一个元素称为一个输入符号. ⒊f是一个从Kx∑*到K的子集映射即K*∑*->2^K,其中2^K表示K的幂集. ⒋S包含于K集,是一个非空初态集合. ⒌Z包含于K是一个非空的终态集合. 确定有穷自动机(DFA) 一个确定的有穷自动机M是一个五元组:M=(K, ∑,f,S,Z)其中, 1)K是一个有穷集,他的每个

&lt;编译原理 - 函数绘图语言解释器(1)词法分析器 - python&gt;

<编译原理 - 函数绘图语言解释器(1)词法分析器 - python> 背景 编译原理上机实现一个对函数绘图语言的解释器 - 用除C外的不同种语言实现 解释器分为三个实现块: 词法分析器:用于识别一条语句中的关键词是否符合预先定义的规则. 语法分析器:用来确定一条语句是否满足语法规则. 解释器:用来确定满足语法规则的句子,在意思上是否符合要求. 设计思路: 设计记号:词法分析器读取一个序列并根据构词规则把序列转化为记号流 定义一个字典:把所有符合一个模式的保留字.常量名.参数名.函数名等放进字

&lt;编译原理 - 函数绘图语言解释器(3)解释器 - python&gt;

<编译原理 - 函数绘图语言解释器(3)解释器 - python> 背景 编译原理上机实现一个对函数绘图语言的解释器 - 用除C外的不同种语言实现 设计思路: 将语法分析器并入绘图功能 继承语法分析器覆盖重写 用Pycharm写了一个.py文件: parserclass.py 输入流是语法分析器得到的语法树,输出流是绘制的图像 测试文本序列: //----------------测试程序1:分别测试------------------------ ORIGIN IS (100,300); //

编译原理学习基本概念汇总

对于计算机专业的学生来说,肯定听说过或者上过一门课,叫做--编译原理,被称为计算机专业的天书,反正不管是学习这门课的时候,还是现在,我都是没搞懂其中的技术和知识.但就期末考试而言,提前做了几道题目,得到了90+的分数,也算是可喜可贺.各位ITer如果想检验自己的智商的话,大可以去学习编译原理,你会收获很多的.现在我把大学时整理的编译原理最基本的概念分享出来. 第一章-绪论 1. 翻译,是指在计算机中放置一个能由计算机直接执行的翻译程序,它以某一种程序设计语言(源语言)所编写的程序(源程序)作为翻

[编译原理学习]词法分析

此前一直没能系统完整地学过编译原理,只有很粗浅的理解,虽然其实对工作里的任务也没啥影响,但总觉得缺了一大块知识,加上对所谓程序员三大浪漫(编译器,操作系统,图形学)的向往,所以最近跟着网易云课堂推出的计算机专业课程来学习编译原理.无奈生性懒惰,常常下班之后觉得累了,打打游戏啊看看视频啊,拖延症就犯了.......所以在这里打算将学习的过程,心得记录下来,也算是对自己的一个督促.课程传送门http://mooc.study.163.com/learn/USTC-1000002001#/learn/

编译原理学习随笔

编译原理就是什么? 编译原理是计算机必修的一门重要学科.编译原理及技术从本质上来讲就是一个算法问题而已,当然由于这个问题十分复杂,其解决算法也相对复杂. 我们学的数据结构与算法分析也是讲算法的,不过讲的基础算法,换句话说讲的是算法导论,而编译原理这门课程讲的就是比较专注解决一种的算法了. 学习编译原理有什么好处? 可以大大提高我们的编程能力,能更好的了解计算机内部运行结果,对进一步研究计算机系统有很大帮助,同时学会了编译原理也相当于学会了一种解决问题的方法,而且是强有力的方法.能让你一直在寻求高