分享
 
 
 

little c原代码分析[一]

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

此代码为c语言大全这本书作者实现的little c解释器的原代码,下面是部分分析。这是第1篇文章

/* Get a token. */

/* -------------------------------------------------------------------- */

/* 功能:此程序是从字符流中取得一个”单词“,把单词从字符中匹配出来 */

/* -------------------------------------------------------------------- */

/* 变量说明: */

/* token_type:这个变量是用来说明组成的关键字和的类型的类型 */

/* tok: 此为存放关键字 */

/* token: 此为存放字符串,数字等所有符号的值 */

/* temp: 此为token指针的缓冲区,主要是解决了指针移动的方便的问题 */

/* --------------------------------------------------------------------- */

int get_token(void)

{

register char *temp;

token_type = 0; tok = 0;

temp = token;

/* temp 为token的缓冲值 */

*temp = '\0';

/* skip over white space */

while(iswhite(*prog) && *prog) ++prog;

/* iswhite标准库函数在此的功能是跳过原代码中的关键字,如果是空白符号的话,那么就跳过 */

if(*prog == '\r') {

++prog;

++prog;

/* 如果是换行符的话,也跳过,字符流指针prog地址加1 */

/* skip over white space */

while(iswhite(*prog) && *prog) ++prog;

}

/* 在新行中如果有空白符号的话,那么也是忽略掉 */

if(*prog == '\0') { /* end of file */

/* 如果prog指针到达文件结尾,prog的值中存放的是'\0' */

*token = '\0';

/* *token给值为'\0' */

tok = FINISHED;

/* tok变量为本解释器的内部关键字类型,这里是表示达到文件结尾,结束 */

return (token_type = DELIMITER);

/

}

/* 此为程序块 */

if(strchr("{}", *prog)) { /* block delimiters */

*temp = *prog;

temp++;

*temp = '\0';

prog++;

return (token_type = BLOCK);

}

/* look for comments */

/* 处理注释部分,如果是/ '+' *字符开头的,表示其是注释,然后是以* '+' /作为结尾的 */

if(*prog == '/')

if(*(prog+1) == '*') { /* is a comment */

prog += 2;

do { /* find end of comment */

while(*prog != '*') prog++;

prog++;

} while (*prog != '/');

prog++;

}

/* 处理! < > =这几个运算符号 */

if(strchr("!<>=", *prog)) { /* is or might be a relational operator */

switch(*prog) {

case '=': if(*(prog+1) == '=') {

/* 如果=后面还是一个=符号的话,那么此单词为内部符号EQ */

prog++; prog++;

*temp = EQ;

temp++; *temp = EQ; temp++;

*temp = '\0';

}

break;

case '!': if(*(prog+1) == '=') {

/* 如果是!加=符号的话,那么prog就是内部符号NE */

prog++; prog++;

*temp = NE;

temp++; *temp = NE; temp++;

*temp = '\0';

}

break;

case '<': if(*(prog+1) == '=') {

/* 如果是<符号加=符号的话,那么就是内部符号LE */

prog++; prog++;

*temp = LE; temp++; *temp = LE;

}

else {

prog++;

/* 否则就是内部符号LT */

*temp = LT;

}

temp++;

*temp = '\0';

break;

case '>': if(*(prog+1) == '=') {

/* 如果符号是>加=符号的话,那么就是内部运算符号布尔运算符号GE */

prog++; prog++;

*temp = GE; temp++; *temp = GE;

}

else {

prog++;

/* 否则就是内部布尔运算符号GT */

*temp = GT;

}

temp++;

*temp = '\0';

break;

}

if(*token) return (token_type = DELIMITER);

}

/* 下面是测试是否是算术运算符 */

if(strchr("+-*^/%=;(),'", *prog)){ /* delimiter */

*temp = *prog;

prog++; /* advance to next position */

temp++;

*temp = '\0';

return (token_type = DELIMITER);

/* 返回类型为DELIMITER,此类型为算术运算符号 */

}

if(*prog=='"') { /* quoted string */

/* 如果是"符号的话,那么就表示是字符串 */

prog++;

/* 只要不等于"符号,那么就把所有的东西全部放到temp里 */

while(*prog != '"'&& *prog != '\r') *temp++ = *prog++;

if(*prog == '\r') sntx_err(SYNTAX);

prog++; *temp = '\0';

return (token_type = STRING);

/* 返回类型为字符串 */

}

if(isdigit(*prog)) { /* number */

/* 如果是一个数字的话,把所有的数字字符连接起来 */

while(!isdelim(*prog)) *temp++ = *prog++;

*temp = '\0';

return (token_type = NUMBER);

}

if(isalpha(*prog)) { /* var or command */

/* 如果是一个变量或是关键字的话,那么也是把符号组成单词 */

while(!isdelim(*prog)) *temp++ = *prog++;

token_type = TEMP;

}

*temp = '\0';

/* see if a string is a command or a variable */

if(token_type==TEMP) {

tok = look_up(token); /* convert to internal rep */

/* 去符号表中查找是否是关键字 */

if(tok) token_type = KEYWORD; /* is a keyword */

/* 如果tok为真的话,那么这个单词就是关键字 */

else token_type = IDENTIFIER;

/* 否则这个就是变量的名 */

}

return token_type;

}

listing 2

/* Display an error message. */

void sntx_err(int error)

{

char *p, *temp;

int linecount = 0;

register int i;

/* 此字符指针数组里存放的是语法分析时的错误消息 */

static char *e[]= {

"syntax error",

"unbalanced parentheses",

"no expression present",

"equals sign expected",

"not a variable",

"parameter error",

"semicolon expected",

"unbalanced braces",

"function undefined",

"type specifier expected",

"too many nested function calls",

"return without call",

"parentheses expected",

"while expected",

"closing quote expected",

"not a string",

"too many local variables",

"division by zero"

};

printf("\n%s", e[error]);

p = p_buf;

while(p != prog) { /* find line number of error */

p++;

if(*p == '\r') {

linecount++;

}

}

printf(" in line %d\n", linecount);

temp = p;

for(i=0; i < 20 && p > p_buf && *p != '\n'; i++, p--);

for(i=0; i < 30 && p <= temp; i++, p++) printf("%c", *p);

longjmp(e_buf, 1); /* return to safe point */

}

listing 3

/* Recursive descent parser for integer expressions

which may include variables and function calls.

*/

#include <setjmp.h>

#include <math.h>

#include <ctype.h>

#include <stdlib.h>

#include <string.h>

#include <stdio.h>

#define NUM_FUNC 100

#define NUM_GLOBAL_VARS 100

#define NUM_LOCAL_VARS 200

#define ID_LEN 31

#define FUNC_CALLS 31

#define PROG_SIZE 10000

#define FOR_NEST 31

/* 标记类型 主要是标记是什么类型的,是数字,是字符,是块,是字符串等等.*/

enum tok_types {DELIMITER, IDENTIFIER, NUMBER, KEYWORD,

TEMP, STRING, BLOCK};

/* 内部关键字值定义 */

enum tokens {ARG, CHAR, INT, IF, ELSE, FOR, DO, WHILE,

SWITCH, RETURN, EOL, FINISHED, END};

/* 操作符定义 大于,等于,小于等算术操作符的内部形式 */

enum double_ops {LT=1, LE, GT, GE, EQ, NE};

/* These are the constants used to call sntx_err() when

a syntax error occurs. Add more if you like.

NOTE: SYNTAX is a generic error message used when

nothing else seems appropriate.

*/

/* 错误消息的定义 */

enum error_msg

{SYNTAX, UNBAL_PARENS, NO_EXP, EQUALS_EXPECTED,

NOT_VAR, PARAM_ERR, SEMI_EXPECTED,

UNBAL_BRACES, FUNC_UNDEF, TYPE_EXPECTED,

NEST_FUNC, RET_NOCALL, PAREN_EXPECTED,

WHILE_EXPECTED, QUOTE_EXPECTED, NOT_TEMP,

TOO_MANY_LVARS, DIV_BY_ZERO};

/* prog函数是little c脚本语言的程序代码的指针变量 */

extern char *prog; /* current location in source code */

/* 缓冲prog,因为有时,分析可能会出现回朔,所以作者设置了此指针变量 */

extern char *p_buf; /* points to start of program buffer */

extern jmp_buf e_buf; /* hold environment for longjmp() */

/* An array of these structures will hold the info

associated with global variables.

*/

/* 变量属性结构 */

extern struct var_type {

char var_name[32]; /* 变量名字,名字最多允许32个字符 */

int v_type; /* 变量类型 */

int value; /* 变量的值 */

} global_vars[NUM_GLOBAL_VARS];

/* This is the function call stack. */

/* 函数调用堆栈 */

extern struct func_type {

char func_name[32]; /* 函数名字 名字最大为32个字符*/

int ret_type; /* 返回类型 */

char *loc; /* location of function entry point in file */

} func_stack[NUM_FUNC];

/* Keyword table */

/* 关键字结构 */

extern struct commands {

char command[20];

char tok;

} table[];

/* "Standard library" functions are declared here so

they can be put into the internal function table that

follows.

*/

/* 下面的几个函数声明是little c内部函数 */

int call_getche(void), call_putch(void);

int call_puts(void), print(void), getnum(void);

/* 内部函数结构 */

struct intern_func_type {

char *f_name; /* function name */

int (*p)(); /* pointer to the function */

} intern_func[] = {

"getche", call_getche,

"putch", call_putch,

"puts", call_puts,

"print", print,

"getnum", getnum,

"", 0 /* null terminate the list */

};

/* ----------------------------------------------------------- */

/* 变量说明: */

/* token: 此变量是存放单词符号 */

/* token_type: 此变量是存放单词的类型 */

/* tok: 此变量是存放内部关键字的值 */

/* ------------------------------------------------------------*/

extern char token[80]; /* string representation of token */

extern char token_type; /* contains type of token */

extern char tok; /* internal representation of token */

/* 存放用户定义的函数的返回值 */

extern int ret_value; /* function return value */

/* start 下面函数是表达式递归调用分析的子程序 */

void eval_exp0(int *value);

void eval_exp(int *value);

void eval_exp1(int *value);

void eval_exp2(int *value);

void eval_exp3(int *value);

void eval_exp4(int *value);

void eval_exp5(int *value);

/* end */

/* 函数atom 是取得变量,表达式,函数等运算后的值,并存放在全局变量value里 */

void atom(int *value);

/* 函数sntx_err是向屏幕上显示语法错误,通过整数参数变量error来解释不同的错误 */

/* 函数putback函数是返回一个字符流,就是在分析的时候可能会出现向前看一个字符,当看后需要在返回给原先的字符流 */

void sntx_err(int error), putback(void);

/* assign_var函数是分配一个变量存储空间 */

void assign_var(char *var_name, int value);

/* look_up函数是通过查找字符看是否是关键字表中的值,iswhite是查看字符是否是空白字符 */

int isdelim(char c), look_up(char *s), iswhite(char c);

/* 函数find_var是查找一个变量的值 */

/* get_token函数是从当前的字符流中得到一个解释器内部的单词 */

int find_var(char *s), get_token(void);

/* 从内部函数中查找是否有个*s的内部函数 */

int internal_func(char *s);

/* ??????? */

int is_var(char *s);

/* 找一个用户函数的位置,好使call()函数正确调用这个用户定义的函数 */

char *find_func(char *name);

void call(void);

/*********************************************************************

函数名字:atom

*********************************************************************/

void atom(int *value)

{

int i;

switch(token_type) {

/* 选择token类型 */

case IDENTIFIER:

/* 如果是变量或函数 */

i = internal_func(token);

/* 从内部结构中查找函数名是否存在 */

if(i!= -1) { /* call "standard library" function */

/* 如果不是-1的话,那么表示是内部函数 */

*value = (*intern_func.p)();

/* 通过结构中的函数指针调用内部函数,返回的值放到 value指向地址里 */

}

else if(find_func(token)) { /* call user-defined function */

/* 否则通过函数find_func查找是否是用户定义的函数,如果是的话 */

call();

/* 通过call函数调用用户定义的函数 */

*value = ret_value;

/* 函数的返回值放到value指向的地址里 */

}

else *value = find_var(token); /* get var's value */

/* 否则就认为他是一个变量的名字,通过find_var函数找到token里存放到变量值,然后放到value里 */

get_token();

/* 返回 */

return;

case NUMBER: /* is numeric constant */

/* 如果是一个数字的话 那么通过标准库函数中的atoi(在stdio.h中定义了此函数) 把字符转化为数字类型,以方便表达式计算 */

*value = atoi(token);

get_token();

/* 返回 */

return;

case DELIMITER: /* see if character constant */

/* 如果是一个字符常量的话 */

if(*token == '\'') {

/* 如果是'字符,那么把当前的值放到value里 */

*value = *prog;

prog++;

if(*prog!='\'') sntx_err(QUOTE_EXPECTED);

/* 如果不是以'符号结尾,就抛出语法错误 */

prog++;

get_token();

return ;

}

if(*token==')') return; /* process empty expression */

else sntx_err(SYNTAX); /* syntax error */

default:

sntx_err(SYNTAX); /* syntax error */

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有