關於Basic程式直譯器及編譯原理的簡單化(1)--詞法分析和代數式求值 (轉)
在網上,看到還是有部分愛好者希望能編出自己的.當然,這的確是件難事,許多人都說要去看什麼編譯原理和精通語言,結果讓這些愛好者都望而卻步.但是,當我們親手去做做後,發現要做一個簡單的程式直譯器(就像和Basic)那樣,還是挺容易的.你根本不用去看那些東西,只要你懂C語言,在看了本文後,就可以完成那樣的直譯器.
在網上,有許多大型C語言,語言的編譯器.但當你後看看,竟發現點都看不懂.其實那些東西還是不看為妙.看了本文後,我相信你寧願自己動手編,也不願意去領會那些龐大的原始碼了.
少說費話了,我們開始講解.
這一篇Basic直譯器的程式碼.十分經典.而且十分簡單化.
get_token()是詞彙提取,譬如 PRINT A+B
透過一次get_token(),就在 字串token裡裝上PRINT
再呼叫一次get_token(),token裡就裝上A
再呼叫一次get_token(),token裡就裝上+
再呼叫一次get_token(),token裡就裝上B
很簡單吧!
putback()是將prog指標向回移動一格.
其中包含了詞發分析和十分關鍵的代數式求值get_exp(int *result)
關於它的代數式求值get_exp(int *result),用到遞迴
void get_exp(),level2(),level3(),level4(),level5();
void level6(),primitive(),arith(),unary();
,確實難看懂,不過你儘管拿來用就是了.
話不多說,你看原始碼就是了.最後,我將給你看看C++中完整的原始碼
/*
recursive descent parser for integer expression
which may include variables
*/
#include
#include
#include
#include
#include
#define DELIMITER 1
#define VARIABLE 2
#define NUMBER 3
#define COMMAND 4
#define STRING 5
#define QUOTE 6
#define EOL 9
#define FINISHED 10
extern char *prog; /* holds expression to be analyzed */
extern jmp_buf e_buf; /* hold enviroment */
extern int variables[26]; /* variables */
extern struct commands {
char command[20];
char tok;
} table[];
extern char token[80]; /* holds string representation of token */
extern char token_type; /* contains type of token */
extern char tok; /* holds the internal representation of token */
void get_exp(),level2(),level3(),level4(),level5();
void level6(),primitive(),arith(),unary();
void serror(),putback();
/* entry point into parser */
void get_exp(int *result)
{
get_token();
if (!*token) {
serror(2);
return;
}
level2(result);
putback(); /*return last token read to input stream */
}
/* add or subtract two terms */
void level2(int *result)
{
register char op;
int hold;
level3(result);
while ((op = *token) =='+' || op == '-') {
get_token();
level3(&hold);
arith(op,result,&hold);
}
}
/* multiply or div two factors */
void level3(int *result)
{
register char op;
int hold;
level4(result);
while ((op = *token) == '*' || op == '/' || op == '%') {
get_token();
level3(&hold);
arith(op,result,&hold);
}
}
/* process integer exponent */
void level4(int *result)
{
register char op;
int hold;
level5(result);
if (*token == '^') {
get_token();
level4(&hold);
arith(op,result,&hold);
}
}
/* is a unary + or - */
void level5(int *result)
{
register char op;
op = 0;
if ((token_type==DELIMITER) && *token == '+' || *token == '-' ) {
op = *token;
get_token();
}
level6(result);
if (op) unary(op,result);
}
/* process parenthesized expression */
void level6(int *result)
{
if ((*token == '(') && (token_type == DELIMITER)) {
get_token();
level2(result);
if (*token!=')')
serror(1);
get_token();
}
else
primitive(result);
}
/* find value of number or variable */
void primitive(int *result)
{
switch (token_type) {
case VARIABLE:
*result = find_var(token);
get_token();
return;
case NUMBER:
*result = atoi(token);
get_token();
return;
default:
serror(0);
}
}
/* perfothe specified arithmetic */
void arith(char o,int *r,int *h)
{
register int t,ex;
switch (o) {
case '-':
*r = *r-*h;
break;
case '+':
*r = *r+*h;
break;
case '*':
*r = *r**h;
break;
case '/':
*r = (*r)/(*h);
break;
case '%':
*r = (*r)%(*h);
break;
case '^':
ex = *r;
if (*h==0) {
*r = 1;
break;
}
for (t=*h-1;t>0;--t) *r=(*r)*ex;
break;
}
}
/* reverse the sign */
void unary(char o,int *r)
{
if (o=='-') *r = -(*r);
}
/* find the value of a variable */
int find_var(char *s)
{
if (!isalpha(*s)) {
serror(4); /* not a variable */
return 0;
}
return variables[toupper(*token)-'A'];
}
/* display an error message */
void serror(int error)
{
char *e[] = {
"syntax error",
"unbalanced parentheses",
"no expression present",
"equal sign expected",
"not a variable",
"label table full",
"duplicate label",
"undefined label",
"THEN expected",
"TO expected",
"too many nested FOR ls",
"NEXT without FOR",
"too many nested GOSUB",
"RETURN without GOSUB"
};
printf ("%sn",e[error]);
longjmp(e_buf,1); /* return to save point */
}
/* get a token */
get_token()
{
register char *temp;
token_type = 0;tok = 0;
temp = token;
if (*prog == '') { /* end of file */
*token = 0;
tok = FINISHED;
return (token_type = DELIMITER);
}
while (iswhite(*prog)) ++prog; /* skover white space */
if (*prog == 'r') { /* CR LF */
++prog;++prog;
tok = EOL;*token = 'r';
token[1] = 'n';token[2] = 0;
return (token_type = DELIMITER);
}
if (strchr("+-*^/%=;(),> *temp = *prog;
prog++; /* advance to next position */
temp++;
*temp=0;
return (token_type = DELIMITER);
}
if (*prog == '"') { /* quote string */
prog++;
while (*prog!='"'&&*prog!='r') *temp++=*prog++;
if (*prog=='r') serror(1);
prog++;*temp=0;
return (token_type = QUOTE);
}
if (isdigit(*prog)) { /* number */
while (!isdelim(*prog)) *temp++=*prog++;
*temp = '';
return (token_type = NUMBER);
}
if (isalpha(*prog)) { /* var or command */
while (!isdelim(*prog)) *temp++=*prog++;
token_type = STRING;
}
*temp = '';
/* see if a string is a command or a variable */
if (token_type == STRING) {
tok = look_up(token); /* convert to internal rep */
if (!tok) token_type = VARIABLE;
else token_type = COMMAND; /* is a command */
}
return token_type;
}
/* return a token to input stream */
void putback()
{
char *t;
t = token;
for (;*t;t++) prog--;
}
look_up(char *s)
{
register int i,j;
char *p;
/* convert to lowercase */
p = s;
while (*p) { *p = tolower(*p); p++; }
/* see if token is in table */
for (i=0;*table[i].command;i++)
if (!strcmp(table[i].command,s)) return table[i].tok;
return 0; /* unknown command */
}
/* return true if c is a delimiter */
isdelim(char c)
{
if (strchr(";,+-<>/*%^=() ",c)||c==9||c=='r'||c==0)
return 1;
return 0;
}
iswhite (char c)
{
if (c==' '||c=='t') return 1;
else return 0;
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-996093/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 關於Basic程式直譯器及編譯原理的簡單化(1)---Basic器的語法分析及主要程式碼 (轉)C程式編譯原理語法分析
- 關於Basic程式直譯器及編譯原理的簡單化(2)---C++封裝好的Basic直譯器 (轉)C程式編譯原理C++封裝
- Java 實現《編譯原理》簡單詞法分析功能Java編譯原理詞法分析
- 編譯原理實驗1:詞法分析編譯原理詞法分析
- 編譯原理上機作業1——詞法分析器編譯原理詞法分析
- 【編譯原理】手工打造詞法分析器編譯原理詞法分析
- 用Java寫編譯器(1)- 詞法和語法分析Java編譯語法分析
- 【水汐の編譯原理】 詞法分析器 課題1編譯原理詞法分析
- Go編譯原理系列3(詞法分析)Go編譯原理詞法分析
- 0920編譯原理詞法分析編譯原理詞法分析
- 實現指令碼直譯器 - 詞法分析器指令碼詞法分析
- Go編譯原理系列2(詞法分析&語法分析基礎)Go編譯原理詞法分析語法分析
- 小C語言--詞法分析程式(編譯原理實驗一)C語言詞法分析編譯原理
- 淺談彙編器、編譯器和直譯器編譯
- SQL WHERE IN引數化編譯寫法簡單示例SQL編譯
- 中文詞法分析的簡單程式 (轉)詞法分析
- 編譯程式(compiler)的簡單分析編譯Compile
- 編譯器前端之如何實現基於DFA的詞法分析器編譯前端詞法分析
- 程式的編譯和連結原理分析編譯
- 精讀《手寫 SQL 編譯器 – 詞法分析》SQL編譯詞法分析
- 精讀《手寫 SQL 編譯器 - 詞法分析》SQL編譯詞法分析
- 【編譯原理】手工打造語法分析器編譯原理語法分析
- 從編譯原理看一個直譯器的實現編譯原理
- 【編譯原理】語法分析(三)編譯原理語法分析
- Python直譯器簡介(1):函式物件Python函式物件
- 化繁為簡的翻譯機——直譯器模式模式
- 關於程式的編譯和連結編譯
- 自己動手寫basic直譯器 一
- 程式語言和編譯器書單(1)編譯
- 簡單分析AutoIt指令碼的反編譯和程式碼格式化問題指令碼編譯
- 前端與編譯原理——用 JS 寫一個 JS 直譯器前端編譯原理JS
- 前端與編譯原理——用JS寫一個JS直譯器前端編譯原理JS
- 編譯原理之語法分析-自下而上分析(三)編譯原理語法分析
- 編譯原理之語法分析-自下而上分析(四)編譯原理語法分析
- 小白說編譯原理-9-最簡單minus-c語言編譯器編譯原理C語言
- 程式碼線上編譯器(上)- 編輯及編譯編譯
- 0909關於編譯原理編譯原理
- 編譯原理上機作業2——LL(1)語法分析編譯原理語法分析