?? parse.c
字號:
/********************************************************
* Porject Name:
* Little C Interpretes
* Version & Revision:
* 1.0.1
* Creation Date:
* 2005-02-02
* Author:
* Herbet Schildt & Yock Yu
* Description:
* Recursive descent parser for integer expressions
* which may include variable 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};
/*Rev 1.02 yock.yu 05-02-09*/
enum self_ops{AD = 0x11, DE, AQ, DQ, MQ, VQ, OQ, RQ};
/* ++, --, +=, -=, *=, /=, %=, ^=*/
/*
These are the constants used to all sntx_err()
when a syntax error occurs. Add more if you like.
NOTE:SYNTAX is generic error message used when
noting 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,
NO_TEMP, TOO_MANY_LVARS, DIV_BY_ZERO};
extern char *prog; /* current location in source code */
extern char *p_buf; /* points to start of program buffer */
extern jmp_buf e_buf; /* hold enviorment for longjmp() */
/*
An array of these structures will hold
the info associated with global variables.
*/
extern struct var_type{
char var_name[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];
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.
*/
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 */
};
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 */
void eval_exp(int *value);
void eval_exp0(int *value), eval_exp1(int *value);
void eval_exp2(int *value), eval_exp3(int *value);
void eval_exp4(int *value), eval_exp5(int *value);
void atom(int *value);
void sntx_err(int error), putback(void);
void assign_var(char *var_name, int value);
int isdelim(char c), look_up(char *s), iswhite(char c);
int find_var(char *s), get_token(void);
int internal_func(char *s);
extern int is_var(char *s);
extern char *find_func(char *name);
extern void call(void);
/* Entry point into parser */
void eval_exp(int *value)
{
get_token();
if(!*token){
sntx_err(NO_EXP);
return;
}
if(*token == ';'){
*value = 0; /* empty expression */
return;
}
eval_exp0(value);
putback();/* return last token read to input stream */
}
/* Process an assignment expression */
void eval_exp0(int *value)
{
char temp[ID_LEN]; /* holds name of var receiving the assignment*/
register int temp_tok;
if(token_type == IDENTIFIER){
if(is_var(token)){ /* if a var, see if assignment */
strcpy(temp, token);
temp_tok = token_type;
get_token();
if(*token == '='){ /* is an assignment */
get_token();
eval_exp0(value); /* get value to assignment */
assign_var(temp, *value); /* assign the value */
return;
}
else{ /* not an assignment */
putback(); /* restore original token */
strcpy(token, temp);
token_type = temp_tok;
}
}
}
eval_exp1(value);
}
/* Process relatonal operators. */
void eval_exp1(int *value)
{
int partial_value;
int t;/*Rev 1.03 yock.yu 05-02-12*/
char temp[ID_LEN];/*Rev 1.03 yock.yu 05-02-12*/
register char op;
char relops[7]={LT, LE, GT, GE, EQ, NE, 0};
char dualops[7]={AQ, DQ, MQ, VQ, OQ, RQ, 0};/* Rev 1.03 yock.yu 05-02-12*/
strcpy(temp, token);
eval_exp2(value);
op = *token;
/* Rev 1.03 yock.yu 05-02-12 start*/
if(strchr(dualops, op)){
get_token();
eval_exp2(&partial_value);
switch(op){
case AQ:
*value = *value + partial_value;
break;
case DQ:
*value = *value - partial_value;
break;
case MQ:
*value = *value * partial_value;
break;
case VQ:
if(partial_value == 0)
sntx_err(DIV_BY_ZERO);
*value = *value / partial_value;
break;
case OQ:
break;
case RQ:
t = (*value) / partial_value;
*value = *value - (t * partial_value);
break;
}
assign_var(temp, *value);
return;
}
/* Rev 1.03 yock.yu 05-02-12 end*/
if(strchr(relops, op)){
get_token();
eval_exp2(&partial_value);
switch(op){ /* perform the relation operation */
case LT:
*value = *value < partial_value;
break;
case LE:
*value = *value <= partial_value;
break;
case GT:
*value = *value > partial_value;
break;
case GE:
*value = *value >= partial_value;
break;
case EQ:
*value = *value == partial_value;
break;
case NE:
*value = *value != partial_value;
break;
}
}
}
/* Add or subtract two terms. */
void eval_exp2(int *value)
{
register char op;
int partial_value;
eval_exp3(value);
while((op = *token) == '+' || op == '-'){
get_token();
eval_exp3(&partial_value);
switch(op){ /* add or subtract */
case '+':
*value = *value + partial_value;
break;
case '-':
*value = *value - partial_value;
break;
}
}
}
/* Multiply or divide two factors. */
void eval_exp3(int *value)
{
register char op;
int partial_value, t;
eval_exp4(value);
while((op = *token) == '*' || op == '/' || op == '%'){
get_token();
eval_exp(&partial_value);
switch(op){ /* mul, div, or modulus */
case '*':
*value = *value * partial_value;
break;
case '/':
if(partial_value == 0)
sntx_err(DIV_BY_ZERO);
*value = *value / partial_value;
break;
case '%':
t = (*value) / partial_value;
*value = *value - (t * partial_value);
break;
}
}
}
/* Is a unary + or -. */
void eval_exp4(int *value)
{
register char op;
op = '\0';
if(*token == '+' || *token == '-'){
op = *token;
get_token();
}
eval_exp5(value);
if(op)
if(op == '-')
*value = -(*value);
}
/* Process parenthesized expression. */
void eval_exp5(int *value)
{
char temp[ID_LEN];/*Rev 1.02 yock.yu 05-02-11*/
if(*token == '('){
get_token();
eval_exp0(value); /* get subexpressoin */
if(*token != ')')
sntx_err(PAREN_EXPECTED);
get_token();
}
else{
strcpy(temp, token);/*Rev 1.02 yock.yu 05-02-11*/
atom(value);
/*Rev 1.02 yock.yu 05-02-11 start*/
if(*token == AD || *token == DE){
if(*token == AD) ++(*value);
else if(*token == DE) --(*value);
assign_var(temp, *value);
get_token();
}
/*Rev 1.02 yock.yu 05-02-11 end*/
}
}
/* Find value of number, variable, or function. */
void atom(int *value)
{
int i;
switch(token_type){
case IDENTIFIER:
i = internal_func(token);
if(i != -1){ /* call "standard library" function */
*value = (*intern_func[i].p)();
}
else{
if(find_func(token)){ /* call user-defined function */
call();
*value = ret_value;
}
else{
*value = find_var(token); /* get var's value */
}
}
get_token();
return;
case NUMBER: /* is number constant */
*value = atoi(token);
get_token();
return;
case DELIMITER: /* see if character constant */
if(*token == '\''){
*value = *prog;
prog++;
if(*prog != '\'')
sntx_err(QUOTE_EXPECTED);
prog++;
get_token();
return;
}
if(*token == ')') /* process empty expression */
return;
else
sntx_err(SYNTAX); /* syntax error */
default:
sntx_err(SYNTAX); /* syntax error */
}
}
/* Display an error message */
void sntx_err(int error)
{
char *p, *temp;
int linecount = 0;
register int i;
static char *e[]={
"syntax error",
"unbalanced parenthese",
"no expressoin present",
"equals sign expected",
"not a variable",
"parameter error",
"semicolon expected",
"unbalanced braces",
"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 */
}
/* Get a token */
int get_token(void)
{
register char *temp;
token_type = 0;
tok = 0;
temp = token;
*temp = '\0';
/* skip over white space */
while(iswhite(*prog) && *prog) ++prog;
if(*prog == '\r'){
++prog;
++prog;
while(iswhite(*prog) && *prog)
++prog;
}
if(*prog == '\0'){ /* end of file */
*token = '\0';
tok = FINISHED;
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 relation operator */
switch(*prog){
case '=':
if(*(prog + 1) == '='){
prog += 2;
*temp = EQ;
temp++; *temp = EQ; temp++;
*temp = '\0';
}
break;
case '!':
if(*(prog + 1) == '='){
prog += 2;
*temp = NE;
temp++; *temp = NE; temp++;
*temp = '\0';
}
break;
case '<':
if(*(prog + 1) == '='){
prog += 2;
*temp = LE; temp++; *temp = LE;
}
else{
prog++;
*temp = LT;
}
temp++;
*temp = '\0';
break;
case '>':
if(*(prog + 1) == '='){
prog += 2;
*temp = GE; temp++; *temp = GE;
}
else{
prog ++;
*temp = GT;
}
temp++;
*temp = '\0';
break;
}
if(*token)
return(token_type = DELIMITER);
}
if(strchr("+-*/^%=;(),'", *prog)){ /* delimiter */
/* Rev 1.02 yock.yu 05-02-09 start */
if((*prog == '+') && (*(prog + 1) == '+')){
prog += 2;
*temp = AD; temp++; *temp = AD;
}
else if((*prog == '-') && (*(prog + 1) == '-')){
prog += 2;
*temp = DE; temp++; *temp = DE;
}
/* Rev 1.03 yock.yu 05-02-12 start*/
else if(strchr("+-*/^%", *prog) && (*(prog + 1) == '=')){
switch(*prog){
case '+':
*temp = AQ; temp++; *temp = AQ;
break;
case '-':
*temp = DQ; temp++; *temp = DQ;
break;
case '*':
*temp = MQ; temp++; *temp = MQ;
break;
case '/':
*temp = VQ; temp++; *temp = VQ;
break;
case '^':
*temp = RQ; temp++; *temp = RQ;
break;
case '%':
*temp = OQ; temp++; *temp = OQ;
break;
}
prog += 2;
}
/* Rev 1.03 yock.yu 05-02-12 end*/
else{
/* Rev 1.02 yock.yu 05-02-09 end */
*temp = *prog;
prog++; /* advance to next position */
}/*Rev 1.02 yock.yu 05-02-09*/
temp++;
*temp = '\0';
return(token_type = DELIMITER);
}
if(*prog == '"'){ /* quoted string */
prog++;
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 */
else
token_type = IDENTIFIER;
}
return token_type;
}
/* Return a token to input stream */
void putback(void)
{
char *t;
t = token;
for(; *t; t++)
prog--;
}
/*
Look up a token's internal representation
int the table.
*/
int look_up(char *s)
{
register int i;
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 index of internal library function or
-1 if not found.
*/
int internal_func(char *s)
{
register int i;
for(i = 0; intern_func[i].f_name[0]; i++){
if(!strcmp(intern_func[i].f_name, s))
return i;
}
return -1;
}
/* Return 1 if c is a delimiter. */
int isdelim(char c)
{
if(strchr(" !;,+-<>'/*%^=()", c) || c == 9 ||
c == '\r' || c == 0)
return 1;
return 0;
}
/* Return 1 if c is space or tab. */
int iswhite(char c)
{
if(c == ' ' || c == '\t')
return 1;
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -