C语言 词法分析器-简单函数绘图语言的解释器

先写一个词法分析器
把源码放在项目目录中,命名为“test.txt”,或者修改一下代码
生成词法分析结果
函数绘图语言源码示例
在这里插入图片描述
在这里插入图片描述

#include "pch.h"
#include <iostream>
#include <graphics.h>      // 引用图形库头文件
#include <conio.h>
#include "pch.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define TOKEN_LEN 100000 
#define TOKEN_BUF 100

enum Token_Type			  // 记号的类别,共22个
{
	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			  // 出错记号(非法输入)
};
struct Token		// 记号的数据结构
{
	Token_Type  type;	// 类别
	char  lexeme[TOKEN_BUF];	// 属性,原始输入的字符串
	double value;		// 属性,若记号是常数则是常数的值
	double(*FuncPtr)(double);
	// 属性,若记号是函数则是函数指针
};
static Token TokenTab[] =
{
	{CONST_ID,	"PI",		3.1415926,	NULL},
	{CONST_ID,	"E",		2.71828,	NULL},
	{T,			"T",		0.0,		NULL},
	{FUNC,		"SIN",		0.0,		sin},
	{FUNC,		"COS",		0.0,		cos},
	{FUNC,		"TAN",		0.0,		tan},
	{FUNC,		"LN",		0.0,		log},
	{FUNC,		"EXP",		0.0,		exp},
	{FUNC,		"SQRT",		0.0,		sqrt},
	{ORIGIN,	"ORIGIN",	0.0,		NULL},
	{SCALE,		"SCALE",	0.0,		NULL},
	{ROT,		"ROT",		0.0,		NULL},
	{IS,		"IS",		0.0,		NULL},
	{FOR,		"FOR",		0.0,		NULL},
	{FROM,		"FROM",		0.0,		NULL},
	{TO,		"TO",		0.0,		NULL},
	{STEP,		"STEP",		0.0,		NULL},
	{DRAW,		"DRAW",		0.0,		NULL}
};

char source[100000];
static char TokenBuf[TOKEN_BUF];              //记号字符缓冲
Token token[TOKEN_LEN];//记号
/*char *enumoutput(int i)
{
	char s[10];
	switch (i)
	{
		case 1:
			strcpy(s, "ORIGIN");
			break;
	}
	return s;
}*/
int Infile()//文件读入
{
	int i = 0;
	FILE *fp;
	char ch, fpname[100] = "test.txt";
	if ((fp = fopen(fpname, "r")) == NULL)
	{
		printf("Can not find the file.\n");
		exit(0);
	}
	else {
		while (!feof(fp))
		{
			fscanf(fp, "%c", &ch); 
			
			if (ch == '\t') {//跳过/t
				while (1)
				{
					if (EOF == fscanf(fp, "%c", &ch) || ch != '\t')break;
				}
			}
			if (ch >= 'a'&&ch <= 'z')ch -= 32;//小写转化大写
			//下面跳过注释
			if (ch == '/'&&source[i-1] == '/')//找到注释//
			{
				while(1)
				{
					if (EOF == fscanf(fp, "%c", &ch) || ch == '\n' )break;//当找到换行或者文件结束时跳出
				}
				source[i-1] = NULL;
				i--;
			}
			if (ch == '-'&&source[i - 1] == '-')//找到注释--
			{
				while (1)
				{
					if (EOF == fscanf(fp, "%c", &ch) || ch == '\n')break;//当找到换行或者文件结束时跳出
				}
				source[i - 1] = NULL;
				i--;
			}
			//跳过注释结束
			source[i] = ch;
			i++;
		}
		source[i - 1] = '\0';
	}
	return i;//返回长度
}
void output(int len)
{
	int i = 0;
	//int length = strlen(source);
	while (i<len)
	{
		printf("%d\t\t%s\t\t%f\t\t%x\n", token[i].type, token[i].lexeme, token[i].value, token[i].FuncPtr);
		//printf("%s\t\t%s\t\t%f\t\t%x\n", enumoutput(int(token[i].type)), token[i].lexeme, token[i].value, token[i].FuncPtr);
		i++;
	}
	printf("\n");
}
Token judgetoken(const char *IDString)//??
{
	int len;
	for (len = 0; len < sizeof(TokenTab) / sizeof(TokenTab[0]); len++)
	{
		if (strcmp(TokenTab[len].lexeme, IDString) == 0)  
			return TokenTab[len];
	}
	Token p;
	memset(&p, 0, sizeof(Token));
	p.type = ERRTOKEN;
	return p;
}
int work()
{
	int length = strlen(source);
	int i = 0 , j , k = 0 , kuohaoflag = 0 ;
	int token_len = 0;
	

	for ( ; i < length ; i++)
	{
		if (isalpha(source[i]))//判断是否为英文字母
		{
			k = 0;//初始化k
		    j = i;
			loop1:
			TokenBuf[k] = source[j];
			j++;
			k++;
			if (isalnum(source[j]))//如果下一个是字母或者数字
			{
				goto loop1;
			}
			else {
				
			}
			//判断是否token的类别
			token[token_len] = judgetoken(TokenBuf);
			//赋值token的类型与属性
			token_len++;
			memset(TokenBuf, 0x00, k);//字符串数组中所有元素全部设置为\0即可
			i = j - 1;//跳过中间那些字母或数字,进入其他符号(比如+-*/空格)
		}
		else if (isdigit(source[i]))//若是一个数字,则一定是常量
		{
			j = i;
			k = 0;
			TokenBuf[k] = source[i];
			k++;
			while (1)
			{
				j++;
				if (isdigit(source[j]))
				{
					TokenBuf[k] = source[j];
					k++;
				}
				else break;
			}
			if (source[j] == '.')//如果是小数
			{
				TokenBuf[k] = source[j];//‘.’进入记号字符缓冲区
				k++;
				j++;
				if (isdigit(source[j]))//小数点后仍是数字
				{
					TokenBuf[k] = source[j];
					k++;
					while (1)
					{
						j++;
						if (isdigit(source[j]))
						{
							TokenBuf[k] = source[j];
							k++;
						}
						else break;
					}
				}
				else {
					//小数点后不是数字,非法输入
					i = j - 1;
					goto loop2;
				}

				
			}
			//把数字字符串转化为double
			strcpy(token[token_len].lexeme, TokenBuf);
			token[token_len].type = CONST_ID;
			token[token_len].value = atof(TokenBuf);//字符串转化为double
			token_len++;
			memset(TokenBuf, 0x00, k);//字符串数组中所有元素全部设置为\0即可
			i = j - 1;

		}
		else {//不是字母和数字,则一定是运算符或分隔符
			switch (source[i])
			{
			case ';':
				token[token_len].type = SEMICO;
				strcpy(token[token_len].lexeme, ";");
				token_len++;
				break;
			case ',':
				token[token_len].type = COMMA;
				strcpy(token[token_len].lexeme, ",");
				token_len++;
				break;
			case '+':
				token[token_len].type = PLUS;
				strcpy(token[token_len].lexeme, "+");
				token_len++;
				break;
			case '-':
				token[token_len].type = MINUS;
				strcpy(token[token_len].lexeme, "-");
				token_len++;
				break;
			case '*':
				if (source[i + 1] == '*')
				{
					token[token_len].type = POWER;
					strcpy(token[token_len].lexeme, "**");
					token_len++;
					i++;
				}
				else {
					token[token_len].type = MUL;
					strcpy(token[token_len].lexeme, "*");
					token_len++;
				}
				break;
			case '/':
				token[token_len].type = DIV;
				strcpy(token[token_len].lexeme, "/");
				token_len++;
				break;
			case '(':
				token[token_len].type = L_BRACKET;
				strcpy(token[token_len].lexeme, "(");
				token_len++;
				kuohaoflag++;
				break;
			case ')':
				token[token_len].type = R_BRACKET;
				strcpy(token[token_len].lexeme, ")");
				token_len++;
				kuohaoflag--;
				break;
			case ' ':
				break;
			case '\n':
				break;
			default :
				loop2:
				token[token_len].type = ERRTOKEN;
				strcpy(token[token_len].lexeme, "ERRTOKEN");
				token_len++;
				break;
			}
		}

	}
	//最后面代码分析结束时加入程序结束的空记号
	token[token_len].type = NONTOKEN;
	strcpy(token[token_len].lexeme, "NONTOKEN");
	token_len++;
	return token_len;
}
int main()
{
	//int length;
	Infile();
	
	int i=work();
	output(i);
}

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值