關於Basic程式直譯器及編譯原理的簡單化(1)--詞法分析和代數式求值 (轉)

worldblog發表於2007-12-29
關於Basic程式直譯器及編譯原理的簡單化(1)--詞法分析和代數式求值 (轉)[@more@]

  在網上,看到還是有部分愛好者希望能編出自己的.當然,這的確是件難事,許多人都說要去看什麼編譯原理和精通語言,結果讓這些愛好者都望而卻步.但是,當我們親手去做做後,發現要做一個簡單的程式直譯器(就像和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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章