作业模拟实现词法分析器,记录一下。

题目:

一、待分析的C语言子集的词法

1. 关键字
main if else int return void while (都是小写)2. 专用符号
= + — * / < <= < >= = = != ; : ,{ } [ ] ( )3. 其他标记
STRING::= " [^"]* "
 ID::=letter(letter|digit)*
 INT::=digit digit*
 letter::= a|…|z|A|…|Z
 digit::= 0|…|9
  1. 空格由空白、制表符和换行符组成
    空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。

二、部分单词符号对应的种别码(可自行扩展)

单词符号 种别码 单词符号 种别码

编写词法分析程序Java核心代码_编写词法分析程序Java核心代码


三、词法分析程序的功能

输入:所给文法的源程序字符串

输出:二元组(syn, token或sum)构成的序列。其中syn 为单词种别码;token 为存放的单词自身字符串;sum为整型常量(作为常量的值)。实现时,可将单词的二元组用结构进行处理。

思路:

词法分析器就是把代码分成一个一个的单词,所以函数主体就是对单个单词进行分类。
从文件读入字符,然后对字符进行判断;

  • 如果第一个字符是字母,就放入暂存单词数组,并且后面只要是字母或者数字或者_都加入存入数组,然后再和保留字数组中的保留字一一对比,符合就是相应的保留字,否则就是标识符。
  • 如果第一个字符是数字,那么只要是数字或者.都放入暂存数组,直都不符合,已经存入的就是常量。
  • 如果第一个字符是各种符号,直接用switch就好了。
  • 最后外面再弄一个循环不停地调用函数,每调用一次就识别一个单词,然后进行输出,一直到最后结束循环,词法分析完成。

源码:

#include<iostream>
#include<fstream>
using namespace std;
#define M 12
#define wordNum 10//关键字数量
const int max_word = 505;
char token[M] ;
char in[105];
FILE* fin, * fout;
int cnt = 0, token_num = 0;
int row = 1;
int flag = 0;
char ch;
//关键字 
const char keyWord[wordNum][20] = { "main","int","char","if","else","for","while",
"return","void" };
void setNULL() {
	for (int i = 0; i < M; i++) {
		token[i] = NULL;
	}
}



int judge_token() {
	setNULL();
	if (flag == 0) {
		ch = getc(fin);
	}
	flag = 1;
	while (ch == ' ' || ch == '\t' || ch == '\n') {//遇到这些就继续获取后面的内容
		if (ch == '\n') {//遇上换行符就行号加一
			row++;
		}
		ch = getc(fin);
	}
	token_num = 0;
	if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
		//可能为标识符或者变量名 
		while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) {
			token[token_num++] = ch;
			ch = getc(fin);
		}
		token[token_num++] = '\0';
		for (int i = 0; i < wordNum; i++) {
			if (strcmp(token, keyWord[i]) == 0) {
				//关键词字
				return i+1;
			}
		}
		//标识符 
		return 10;
	}
	//第一个是数字 
	else if (ch >= '0' && ch <= '9') {
		while ((ch >= '0' && ch <= '9') || ch == '.') {
			token[token_num++] = ch;
			ch = getc(fin);
		}
		return 20;//常量
	}
	else {
		token[token_num++] = ch;
		switch (ch) {
		case '(': ch = getc(fin); return 26;
		case ')': ch = getc(fin); return 27;
		case '[': ch = getc(fin); return 28;
		case ']': ch = getc(fin); return 29;
		case '{': ch = getc(fin); return 30;
		case '}': ch = getc(fin); return 31;
		case '+':
			ch = getc(fin);
			if (ch == '+') {
				token[token_num++] = ch;
				ch = getc(fin);
				return 41;//递增
			}
			else {
				return 22;//加号
			}
		case '-':
			ch = getc(fin);
			if (ch == '-') {
				token[token_num++] = ch;
				ch = getc(fin);
				return 42;//递减
			}
			else {
				return 23;//减号
			}
		case '*':ch = getc(fin); return 24;
		case '/':
			ch = getc(fin);
			if (ch == '/') {
				token[token_num++] = ch;
				ch = getc(fin);
				return 43;//注释
			}
			else {
				return 25;//除号
			}
			//这里要重新编码 
		case '=':
			ch = getc(fin);
			if (ch == '=') {
				token[token_num++] = ch;
				ch = getc(fin);
				return 29;//比较符号
			}
			else {
				return 21;//赋值符号
			}
		case '>':
			ch = getc(fin);
			if (ch == '=') {
				token[token_num++] = ch;
				ch = getc(fin);
				return 37;//大于等于
			}
			else if (ch == '>') {
				token[token_num++] = ch;
				ch = getc(fin);
				return 44;//输入符号或者右移符号
			}
			else {
				return 35;//大于号
			}
		case '<':
			ch = getc(fin);
			if (ch == '=') {
				token[token_num++] = ch;
				ch = getc(fin);
				return 38;//小于等于号
			}
			else if(ch=='<'){//输出符号或者右移符号
				token[token_num++] = ch;
				ch = getc(fin);
				return 45;
			}
			else {
				return 36;//小于号
			}
		case ',': ch = getc(fin); return 32;
		case ':': ch = getc(fin); return 33;
		case ';':ch = getc(fin); return 34;
		case '!':
			ch = getc(fin);
			if (ch == '=') {
				token[token_num++] = ch;
				ch = getc(fin);
				return 40;//不等于
			}
			else {
				return 46;//非
			}
		case EOF: return -1;
		default: ch = getc(fin); return -10;//没考虑到的情况
		}
	}
}

void getWord() {
	int temp;
	while (1) {
		temp = judge_token();
		if (temp == -1) {
			break;//文件已经扫描完毕,结束循环
		}
		switch (temp) {
		case -10:
			cout << "第 " << row << " 行出现错误." << endl;
			break;
		default:
			cout << "<" << temp << "," << token << ">" << endl;
			break;
		}
	}
}

void main() {
	fopen_s(&fin,"C://Users//羽墨轩//source//repos//Project4//ABC.txt", "r");
	getWord();
}