伟大的极客总是听命于自己
:创造是极客唯一的属性
前言
这是笔者的编译原理大作业,从词法分析到语法分析写了两天,然而语义分析却差点要了我的老命,结果最后查出来是个小bug:一个标识符放在了错误的位置,然而这却几乎使我放弃了语义分析的工作。由此观之,写程序要有一个良好的心态。
下面给出解释器要求:
简单函数绘图语言共四种语句:坐标平移(ORIGIN)、比例设置(SCALE)、旋转变换(ROT)、循环绘图(FOR-DRAW);其中前三个都是坐标设置,最后一个语句才能绘制出图形。举例如下:
解释器能够对以上语句进行解释,并绘制出相应的图形。
本项目的开发平台为VS2017,采用C语言编写。
解释器的开发过程为:词法分析器—>语法分析器—>语义分析器兼主程序。
这一节笔者会给出词法分析器的代码实现。
一、基本思路
词法分析核心:打开源文件,过滤无用字符,然后进行记号的识别。
关于记号识别的具体细节:设立一个全局的缓冲区,每次识别新记号前对其刷新。每次从源文件读入一个字符,根据词法规则的DFA对其进行判断,或者得到正确的匹配、或者允许继续读取、或者识别出一个错误的单词。
二、代码实现
1.词法分析器头文件scanner.h
#pragma once
#ifndef SCANNER_H
#define SCANNER_H
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<ctype.h>
#include<stdarg.h>
#include<string.h>
//1.变量定义
extern FILE *P_File; //指向扫描文件的句柄
//*****************************************************************************************************************
/*2.结构定义
Token_Type:枚举类型,记录所有记号种类
Token:记号的结构性质,包括种类、原始字符串、属性值(限常量)、地址值(限函数)
TokenTab:由Token组成的数组,主要记录了字符类的记号(这类记号比较多,包括保留字、参数、函数和常量名,使用这个数组进行匹配区分)
*/
enum Token_Type //记号种类
{
ORIGIN, SCALE, ROT, IS, TO, //保留字
STEP, DRAW, FOR, FROM, //保留字
T, //参数
SEMICO, L_BRACKET, R_BRACKET, COMMA, //分隔符号
PLUS, MINUS, MUL, DIV, POWER, //运算符
FUNC, //函数
CONST_ID, //常数
NONTOKEN, //空记号
ERRTOKEN //出错记号
};
extern struct Token //记号与符号表结构
{
enum Token_Type type; //记号的类型
char *lexeme; //构成记号的字符串,最大长度为100
double value; //若为常数,则是常数的值
double(*FuncPtr)(double); //若为函数,则是函数的指针
};
static char LetterTab[][10] = {
"PI","E","T","SIN","COS","TAN","LN","EXP","SQRT","ORIGIN","SCALE","ROT","IS","FOR","FROM","TO","STEP","DRAW"
};
static struct Token TokenTab[] = //符号表内容
{
{
CONST_ID,LetterTab[0],3.1415926,NULL },
{
CONST_ID,LetterTab[1],2.71828,NULL },
{
T,LetterTab[2],