#include "stdio.h"
#include "stdlib.h"
#include "string.h"
// 关键字数组结束标记
#define _KEY_WORD_END "waiting for your expanding"
char input[255]; // 存放用户输入的一串源程序
char token[255] = "";// 存放当前识别出来的单词(记号)
int p_input; // input 的读取指针,记录读到哪个位置
int p_token; // token 的写入指针
char ch; // 当前读到的单个字符
// 关键字表
char* KEY_WORDS[] = {"begin", "if", "then", "while", "do", "end", _KEY_WORD_END};
// 函数声明
void scaner(); // 词法分析器:取出下一个单词
void factor(); // 因子分析
void term(); // 项分析
void statement(); // 语句分析
void expression(); // 表达式分析
void yucu(); // 语句串分析
void lrparser(); // 递归下降总入口,程序的语法分析主函数
int syn; // 当前单词的类别编码
int kk; // 错误标记,kk=1 代表已经出现错误
void main()
{
kk = 0;
printf("Enter Your words(end with #):");
// 读取输入,直到遇到 #
scanf("%[^#]s", input);
printf("Your words:\n%s\n", input);
scaner(); // 先读取第一个单词
lrparser(); // 启动递归下降语法分析
printf("\npress $ to exit:");
scanf("%[^$]s", input);
}
// 语法分析入口:文法 program → begin 语句串 end
void lrparser()
{
// syn == 1 代表读到 begin
if (syn == 1)
{
scaner();
yucu(); // 分析后面一长串语句
if (syn == 6) // syn == 6 代表读到 end
{
scaner();
// syn == 0 代表读到结束,并且没有报错
if ((syn == 0) && (kk == 0))
printf("\n success\n");
}
else
{
if (kk != 1)
{
printf("\n缺少'end'错误");
kk = 1;
}
}
}
else
{
printf("begin错误");
kk = 1;
}
return;
}
// 语句串:yucu → statement ; statement ; ...
void yucu()
{
statement(); // 分析一条语句
// syn == 26 是分号 ;
while (syn == 26)
{
scaner();
statement();
}
return;
}
// 语句:statement → 标识符 := 表达式
void statement()
{
// syn == 10 代表标识符(变量名)
if (syn == 10)
{
scaner();
// syn == 18 代表赋值符号 :=
if (syn == 18)
{
scaner();
expression(); // 分析等号后面的表达式
}
else
{
printf("赋值号错误");
kk = 1;
}
}
else
{
printf("语句错误");
kk = 1;
}
return;
}
// 表达式:expression → term ( +|- term )*
void expression()
{
term();
// syn13 加号 +,syn14 减号 -
while (syn == 13 || syn == 14)
{
scaner();
term();
}
return;
}
// 项:term → factor ( * | / factor )*
void term()
{
factor();
// syn15 乘号 *,syn16 除号 /
while (syn == 15 || syn == 16)
{
scaner();
factor();
}
return;
}
// 因子:factor → 标识符 | 数字 | ( 表达式 )
void factor()
{
// syn10:标识符;syn11:数字
if (syn == 10 || syn == 11)
scaner();
// syn27:左括号 (
else if (syn == 27)
{
scaner();
expression();
// syn28:右括号 )
if (syn == 28)
scaner();
else
{
printf("')'错误");
kk = 1;
}
}
else
{
printf("表达式错误");
kk = 1;
}
return;
}
// 从 input 取出一个字符,并且移动指针
char m_getch()
{
ch = input[p_input];
p_input = p_input + 1;
return (ch);
}
// 跳过空格、换行等空白字符
void getbc()
{
while (ch == ' ' || ch == 10)
{
ch = input[p_input];
p_input = p_input + 1;
}
}
// 将当前字符拼接到 token 里面
void concat()
{
token[p_token] = ch;
p_token = p_token + 1;
token[p_token] = '\0';
}
// 判断当前字符是不是英文字母
int letter()
{
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
return 1;
else
return 0;
}
// 判断当前字符是不是数字
int digit()
{
if (ch >= '0' && ch <= '9')
return 1;
else
return 0;
}
// 判断 token 是否是关键字,是就返回编号,否则返回 10(标识符)
int reserve()
{
int i = 0;
while (strcmp(KEY_WORDS[i], _KEY_WORD_END))
{
if (!strcmp(KEY_WORDS[i], token))
{
return i + 1;
}
i = i + 1;
}
return 10;
}
// 指针回退一个字符(多读了,退回去)
void retract()
{
p_input = p_input - 1;
}
// 数字转换函数,原版预留,这里没有实现
char* dtb()
{
return NULL;
}
// 词法分析核心:识别单词,给出 syn 类别码
void scaner()
{
p_token = 0;
m_getch();
getbc();
// 如果是字母:标识符 / 关键字
if (letter())
{
while (letter() || digit())
{
concat();
m_getch();
}
retract();
syn = reserve();
return;
}
// 如果是数字
else if (digit())
{
while (digit())
{
concat();
m_getch();
}
retract();
syn = 11;
return;
}
// 如果是运算符、分隔符
else
switch (ch)
{
case '=':
syn = 25;
break;
case '+':
syn = 13;
break;
case '-':
syn = 14;
break;
case '*':
syn = 15;
break;
case '/':
syn = 16;
break;
case '(':
syn = 27;
break;
case ')':
syn = 28;
break;
case ':':
m_getch();
if (ch == '=')
{
syn = 18; // := 赋值符号
}
else
{
retract();
syn = 17;
}
break;
case ';':
syn = 26; // 分号
break;
case '>':
m_getch();
if (ch == '=')
{
syn = 24;
}
else
{
retract();
syn = 23;
}
break;
case '<':
m_getch();
if (ch == '=')
{
syn = 22;
return;
}
retract();
syn = 20;
break;
case '\0':
syn = 0; // 源程序结束标记
break;
default:
syn = -1; // 无法识别的非法字符
}
return;
}
To embed this project on your website, copy the following code and paste it into your website's HTML: