对前面的源码进行改进,增加带参数的main函数,不直接在代码中提供需要分析字串,而是把字串添加到文件中去。
这样更贴近真实情况。
int main(int arc,char*argv[])
{
FILE *fp;
if (arc != 2)
{
printf("usage: %s filename \n", argv[0]);
exit(1);
}
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("can't open %s\n", argv[1]);
exit(1);
}
对架构进行改进,把alpha状态替换成IDEN标识符状态。单独构建一个基本类型表,用来从iden中筛选出基本类型。
单独构建一个界限符表。
写进头文件。
#ifndef _basetype_H
#define _basetype_H
char *basetype[8] = { "int","long","short","unsigned","char","float","double","signed" };
char delim[8] = { '(', ')', '{', '}', ';', '[', ']' ,','};
char oper[5] = { '+', '-', '*', '/', '=' };
#endif //
完整的主程序如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#include "basetype.h"
#define STRMAX 50
//定义状态
typedef enum {START,INT,IDEN,OPER,DELIM,END} state;
void stradd(char*, const char);
bool isbasetype(const char*);
bool isoper(char);
bool isdelim(char);
int main(int arc,char*argv[])
{
FILE *fp;
if (arc != 2)
{
printf("usage: %s filename \n", argv[0]);
exit(1);
}
if ((fp = fopen(argv[1], "r")) == NULL)
{
printf("can't open %s\n", argv[1]);
exit(1);
}
//初始化状态
state cur_state = START;
char s[STRMAX];
int i ;
char c,token[20]="";
//循环取字符
while ((fgets(s, STRMAX, fp)) != NULL)
{
for (i = 0; s[i] != '\n'; i++)
{
c = s[i];
switch (cur_state)
{
case START:
if (isdigit(c))
{
cur_state = INT;
i--;
break;
}
else if (isalpha(c))
{
cur_state = IDEN;
i--;
break;
}
else if (isoper(c))
{
cur_state = OPER;
i--;
break;
}
else if (isdelim(c))
{
cur_state = DELIM;
i--;
break;
}
else if (isspace(c))
{
cur_state = START;
break;
}
else if(c=='\0')
{
cur_state = END;
i--;
break;
}
case INT:
if (isdigit(c))
{
stradd(token, c);
break;
}
else
{
cur_state = START;
printf("分解的数字是: %s\n", token);
strcpy(token, "");
i--;
break;
}
case IDEN:
if (isalpha(c))
{
stradd(token, c);
break;
}
else
{
cur_state = START;
if (isbasetype(token))
printf("分解keyword是: %s\n", token);
else
printf("分解的变量是: %s\n", token);
strcpy(token, "");
i--;
break;
}
case DELIM:
printf("界限符是: %c\n", c);
cur_state = START;
break;
case OPER:
printf("分解的运算符是: %c\n", c);
cur_state = START;
break;
case END:
printf("完全分解完毕\n");
return 0;
}
}
}
return 0;
}
void stradd(char*pstr, const char ch)
{
int len;
len=strlen(pstr);
pstr[len] = ch;
pstr[len + 1] = '\0';
}
bool isbasetype(const char *ptoken)
{
for (int i = 0; i < 8; i++)
{
if (strcmp(ptoken, basetype[i]) == 0)
return true;
}
return false;
}
bool isoper(char ch)
{
for (int i = 0; i < 5; i++)
{
if (ch == oper[i])
return true;
}
return false;
}
bool isdelim(char ch)
{
for (int i = 0; i < 8; i++)
{
if (ch == delim[i])
return true;
}
return false;
}
现在能进行一些简单的分解了,支持算术运算符,基本数据类型。
只能支持整数,纯字母组成的标识符。
下一步再来扩展。预备弄一个预处理掉注释和空行。
另外问题依然很多,怎么识别运算优先级?
怎么识别括号成对?大括号(不在一行内),怎么识别拼写错误?
这类问题不属于词法分析的范畴,而是语义分析的领域。