home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / ddjmag / ddj8908.zip / SCHILDT.LST < prev    next >
File List  |  1989-07-06  |  32KB  |  1,217 lines

  1. BUILDING YOUR OWN C INTERPRETER
  2. by Herbert Schildt
  3.  
  4. [LISTING ONE]
  5.  
  6. /* Recursive descent parser for integer expressions
  7.    which may include variables and function calls.  */
  8. #include "setjmp.h"
  9. #include "math.h"
  10. #include "ctype.h"
  11. #include "stdlib.h"
  12. #include "string.h"
  13. #include "stdio.h"
  14.  
  15. #define NUM_FUNC       100
  16. #define NUM_GLOBAL_VARS 100
  17. #define NUM_LOCAL_VARS  200
  18. #define ID_LEN          31 
  19. #define FUNC_CALLS      31
  20. #define PROG_SIZE     10000
  21. #define FOR_NEST    31
  22.  
  23. enum tok_types {DELIMITER, IDENTIFIER, NUMBER, KEYWORD, TEMP,
  24.             STRING, BLOCK};
  25. enum tokens {ARG, CHAR, INT, IF, ELSE, FOR, DO, WHILE, SWITCH,
  26.              RETURN, EOL, FINISHED, END};
  27. enum double_ops {LT=1, LE, GT, GE, EQ, NE};
  28. /* These are the constants used to call sntx_err() when
  29.    a syntax error occurs.  Add more if you like.
  30.    NOTE: SYNTAX is a generic error message used when
  31.    nothing else seems appropriate.
  32. */
  33. enum error_msg 
  34.      {SYNTAX, UNBAL_PARENS, NO_EXP, EQUALS_EXPECTED,
  35.       NOT_VAR, PARAM_ERR, SEMI_EXPECTED,
  36.       UNBAL_BRACES, FUNC_UNDEF, TYPE_EXPECTED,
  37.       NEST_FUNC, RET_NOCALL, PAREN_EXPECTED,
  38.       WHILE_EXPECTED, QUOTE_EXPECTED, NOT_TEMP,
  39.       TOO_MANY_LVARS};
  40. extern char *prog;  /* current location in source code */
  41. extern char *p_buf;  /* points to start of program buffer */
  42. extern jmp_buf e_buf; /* hold environment for longjmp() */
  43. /* An array of these structures will hold the info
  44.    associated with global variables.
  45. */
  46. extern struct var_type {
  47.   char var_name[32];
  48.   enum variable_type var_type;
  49.   int value;
  50. }  global_vars[NUM_GLOBAL_VARS];
  51. /*  This is the function call stack. */
  52. extern struct func_type {
  53.   char func_name[32];
  54.   char *loc;  /* location of function entry point in file */
  55. } func_stack[NUM_FUNC];
  56. /* Keyword table */
  57. extern struct commands {
  58.   char command[20];è  char tok;
  59. } table[];
  60. /* "Standard library" functions are declared here so
  61.    they can be put into the internal function table that
  62.    follows.
  63. */
  64. int call_getche(void), call_putch(void);
  65. int call_puts(void), print(void), getnum(void);
  66.  
  67. struct intern_func_type {
  68.   char *f_name; /* function name */
  69.   int (* p)();  /* pointer to the function */
  70. } intern_func[] = {
  71.   "getche", call_getche,
  72.   "putch", call_putch,
  73.   "puts", call_puts,
  74.   "print", print,
  75.   "getnum", getnum,
  76.   "", 0  /* null terminate the list */
  77. };
  78. extern char token[80]; /* string representation of token */
  79. extern char token_type; /* contains type of token */
  80. extern char tok; /* internal representation of token */
  81. extern int ret_value; /* function return value */
  82. void eval_exp(int *value), eval_exp1(int *value);
  83. void eval_exp2(int *value);
  84. void eval_exp3(int *value), eval_exp4(int *value);
  85. void eval_exp5(int *value), atom(int *value);
  86. void eval_exp0(int *value);
  87. void sntx_err(int error), putback(void);
  88. void assign_var(char *var_name, int value);
  89. int isdelim(char c), look_up(char *s), iswhite(char c);
  90. int find_var(char *s), get_token(void);
  91. int internal_func(char *s);
  92. int is_var(char *s);
  93. char *find_func(char *name);
  94. void call(void);
  95. /* Entry point into parser. */
  96. void eval_exp(int *value)
  97. {
  98.   get_token(); 
  99.   if(!*token) {
  100.     sntx_err(NO_EXP); 
  101.     return; 
  102.   }
  103.   if(*token==';') {
  104.     *value = 0; /* empty expression */
  105.     return;
  106.   }
  107.   eval_exp0(value); 
  108.   putback(); /* return last token read to input stream */
  109. }
  110. /* Process an assignment expression */
  111. void eval_exp0(int *value)
  112. {è  char temp[ID_LEN];  /* holds name of var receiving 
  113.                          the assignment */
  114.   register int temp_tok;
  115.   if(token_type==IDENTIFIER) {
  116.     if(is_var(token)) {  /* if a var, see if assignment */
  117.       strcpy(temp, token);
  118.       temp_tok = token_type;
  119.       get_token();
  120.       if(*token=='=') {  /* is an assignment */
  121.     get_token();
  122.     eval_exp0(value);  /* get value to assign */
  123.     assign_var(temp, *value);  /* assign the value */
  124.         return;
  125.       }
  126.       else {  /* not an assignment */
  127.     putback();  /* restore original token */
  128.     strcpy(token, temp);
  129.     token_type = temp_tok;
  130.       }
  131.     }
  132.   }
  133.   eval_exp1(value);
  134. }
  135. /* This array is used by eval_exp1().  Because 
  136.    some compilers cannot initialize an array within a 
  137.    function it is defined as a global variable.
  138. */
  139. char relops[7] = {
  140.   LT, LE, GT, GE, EQ, NE, 0
  141. };
  142. /* Process relational operators. */
  143. void eval_exp1(int *value)
  144. {
  145.   int partial_value; 
  146.   register char op;
  147.   eval_exp2(value); 
  148.   op = *token;
  149.   if(strchr(relops, op)) {
  150.     get_token(); 
  151.     eval_exp2(&partial_value); 
  152.     switch(op) {  /* perform the relational operation */
  153.       case LT: 
  154.         *value = *value < partial_value;
  155.         break;
  156.       case LE:
  157.         *value = *value <= partial_value;
  158.         break;
  159.       case GT:
  160.         *value = *value > partial_value;
  161.         break;
  162.       case GE:
  163.         *value = *value >= partial_value;
  164.         break;
  165.       case EQ: 
  166.         *value = *value == partial_value;è        break;
  167.       case NE:
  168.         *value = *value != partial_value;
  169.          break;
  170.     }
  171.   }
  172. }
  173. /*  Add or subtract two terms. */
  174. void eval_exp2(int *value)
  175. {
  176.   register char  op; 
  177.   int partial_value; 
  178.   eval_exp3(value); 
  179.   while((op = *token) == '+' || op == '-') {
  180.     get_token(); 
  181.     eval_exp3(&partial_value); 
  182.     switch(op) {  /* add or subtract */
  183.       case '-':
  184.         *value = *value - partial_value; 
  185.         break; 
  186.       case '+':
  187.         *value = *value + partial_value; 
  188.         break; 
  189.     }
  190.   }
  191. }
  192. /* Multiply or divide two factors. */
  193. void eval_exp3(int *value)
  194. {
  195.   register char  op; 
  196.   int partial_value, t; 
  197.   eval_exp4(value); 
  198.   while((op = *token) == '*' || op == '/' || op == '%') {
  199.     get_token(); 
  200.     eval_exp4(&partial_value); 
  201.     switch(op) { /* mul, div, or modulus */
  202.       case '*':  
  203.         *value = *value * partial_value; 
  204.         break; 
  205.       case '/':
  206.         *value = (*value) / partial_value; 
  207.         break; 
  208.       case '%':
  209.         t = (*value) / partial_value; 
  210.         *value = *value-(t * partial_value); 
  211.         break; 
  212.     }
  213.   }
  214. }
  215. /* Is a unary + or -. */
  216. void eval_exp4(int *value)
  217. {
  218.   register char  op; 
  219.   op = '\0'; 
  220.   if(*token=='+' || *token=='-') {è    op = *token; 
  221.     get_token(); 
  222.   }
  223.   eval_exp5(value); 
  224.   if(op)
  225.     if(op=='-') *value = -(*value); 
  226. }
  227. /* Process parenthesized expression. */
  228. void eval_exp5(int *value)
  229. {
  230.   if((*token == '(')) {
  231.     get_token(); 
  232.     eval_exp0(value);   /* get subexpression */
  233.     if(*token != ')') sntx_err(PAREN_EXPECTED); 
  234.     get_token(); 
  235.   }
  236.   else
  237.     atom(value); 
  238. }
  239. /* Find value of number, variable or function. */
  240. void atom(int *value)
  241. {
  242.   int i;
  243.   switch(token_type) {
  244.   case IDENTIFIER:
  245.     i = internal_func(token);
  246.     if(i!= -1) {  /* call "standard library" function */
  247.       *value = (*intern_func[i].p)();
  248.     }
  249.     else
  250.     if(find_func(token)){  /* call user-defined function */
  251.       call();
  252.       *value = ret_value;
  253.     }
  254.     else  *value = find_var(token);  /* get var's value */
  255.     get_token(); 
  256.     return; 
  257.   case NUMBER: /* is numeric constant */
  258.     *value = atoi(token); 
  259.     get_token();   
  260.     return; 
  261.   case DELIMITER: /* see if character constant */
  262.     if(*token=='\'') {
  263.       *value = *prog;
  264.       prog++;
  265.       if(*prog!='\'') sntx_err(QUOTE_EXPECTED);
  266.       prog++;
  267.       get_token();
  268.     }
  269.     return;
  270.   default:
  271.     if(*token==')') return; /* process empty expression */
  272.     else sntx_err(SYNTAX); /* syntax error */
  273.   }
  274. }è/* Display an error message. */
  275. void sntx_err(int error)
  276. {
  277.   char *p, *temp;
  278.   int linecount = 0;
  279.   register int i;
  280.   static char *e[]= {   
  281.     "syntax error", 
  282.     "unbalanced parentheses", 
  283.     "no expression present",
  284.     "equals sign expected",
  285.     "not a variable",
  286.     "parameter error",
  287.     "semicolon expected",
  288.     "unbalanced braces",
  289.     "function undefined",
  290.     "type specifier expected",
  291.     "too many nested function calls",
  292.     "return without call",
  293.     "parentheses expected",
  294.     "while expected",
  295.     "closing quote expected",
  296.     "not a string",
  297.     "too many local variables"
  298.   }; 
  299.   printf("%s", e[error]); 
  300.   p = p_buf;
  301.   while(p != prog) {  /* find line number of error */
  302.     p++;
  303.     if(*p == '\r') {
  304.       linecount++;
  305.     }
  306.   }
  307.   printf(" in line %d\n", linecount);
  308.   temp = p;
  309.   for(i=0; i<20 && p>p_buf && *p!='\n'; i++, p--);
  310.   for(i=0; i<30 && p<=temp; i++, p++) printf("%c", *p);
  311.   longjmp(e_buf, 1); /* return to save point */
  312. }
  313. /* Get a token. */
  314. get_token(void)
  315. {
  316.   register char *temp;
  317.   token_type = 0; tok = 0;
  318.   temp = token;
  319.   *temp = '\0';
  320.  /* skip over white space */
  321.   while(iswhite(*prog) && *prog) ++prog; 
  322.   if(*prog=='\r') { 
  323.     ++prog; 
  324.     ++prog;
  325.     /* skip over white space */
  326.     while(iswhite(*prog) && *prog) ++prog;
  327.   }
  328.   if(*prog=='\0') { /* end of file */è    *token = '\0';
  329.     tok = FINISHED;
  330.     return(token_type=DELIMITER);
  331.   }
  332.   if(strchr("{}", *prog)) { /* block delimiters */
  333.     *temp = *prog;
  334.     temp++;
  335.     *temp = '\0';
  336.     prog++;
  337.     return (token_type = BLOCK);
  338.   }
  339.   /* look for comments */
  340.   if(*prog=='/')
  341.     if(*(prog+1)=='*') { /* is a comment */
  342.       prog += 2;
  343.       do { /* find end of comment */
  344.         while(*prog!='*') prog++;
  345.         prog++;
  346.       } while (*prog!='/');
  347.       prog++;
  348.     }
  349.   if(strchr("!<>=", *prog)) { /* is or might be
  350.                   a relation operator */
  351.     switch(*prog) {
  352.       case '=': if(*(prog+1)=='=') {
  353.       prog++; prog++;
  354.           *temp = EQ;
  355.           temp++; *temp = EQ; temp++;
  356.       *temp = '\0';
  357.       }
  358.     break;
  359.       case '!': if(*(prog+1)=='=') {
  360.       prog++; prog++;
  361.           *temp = NE;
  362.           temp++; *temp = NE; temp++;
  363.       *temp = '\0';
  364.     }
  365.     break;
  366.       case '<': if(*(prog+1)=='=') {
  367.       prog++; prog++;
  368.           *temp = LE; temp++; *temp = LE;
  369.     }
  370.     else {
  371.       prog++;
  372.       *temp = LT;
  373.     }
  374.         temp++;
  375.     *temp = '\0';
  376.     break;
  377.       case '>': if(*(prog+1)=='=') {
  378.       prog++; prog++;
  379.           *temp = GE; temp++; *temp = GE;
  380.     } 
  381.     else {
  382.       prog++;è      *temp = GT;
  383.     }
  384.         temp++;
  385.     *temp = '\0';
  386.     break;
  387.     }
  388.     if(*token) return(token_type = DELIMITER);
  389.   }
  390.   if(strchr("+-*^/%=;(),'", *prog)){ /* delimiter */
  391.     *temp = *prog;
  392.     prog++; /* advance to next position */
  393.     temp++;
  394.     *temp = '\0'; 
  395.     return (token_type=DELIMITER);
  396.   }
  397.   if(*prog=='"') { /* quoted string */
  398.     prog++;
  399.     while(*prog!='"'&& *prog!='\r') *temp++ = *prog++;
  400.     if(*prog=='\r') sntx_err(SYNTAX);
  401.     prog++; *temp = '\0';
  402.     return(token_type=STRING);
  403.   }
  404.   if(isdigit(*prog)) { /* number */
  405.     while(!isdelim(*prog)) *temp++ = *prog++;
  406.     *temp = '\0';
  407.     return(token_type = NUMBER);
  408.   }
  409.   if(isalpha(*prog)) { /* var or command */
  410.     while(!isdelim(*prog)) *temp++ = *prog++;
  411.     token_type=TEMP;
  412.   }
  413.   *temp = '\0';
  414.   /* see if a string is a command or a variable */
  415.   if(token_type==TEMP) {
  416.     tok = look_up(token); /* convert to internal rep */
  417.     if(tok) token_type = KEYWORD; /* is a keyword */
  418.     else token_type = IDENTIFIER;
  419.   }
  420.   return token_type;
  421. }
  422. /* Return a token to input stream. */
  423. void putback(void) 
  424. {
  425.   char *t; 
  426.   t = token; 
  427.   for(; *t; t++) prog--; 
  428. }
  429. /* Look up a token's internal representation in the
  430.    token table.
  431. */
  432. look_up(char *s)
  433. {
  434.   register int i;
  435.   char *p;
  436.   /* convert to lowercase */è  p = s;
  437.   while(*p){ *p = tolower(*p); p++; }
  438.   /* see if token is in table */
  439.   for(i=0; *table[i].command; i++)
  440.       if(!strcmp(table[i].command, s)) return table[i].tok;
  441.   return 0; /* unknown command */
  442. }
  443. /* Return index of internal library function or -1 if
  444.    not found.
  445. */
  446. internal_func(char *s)
  447. {
  448.   int i;
  449.   for(i=0; intern_func[i].f_name[0]; i++) {
  450.     if(!strcmp(intern_func[i].f_name, s))  return i;
  451.   }
  452.   return -1;
  453. }
  454. /* Return true if c is a delimiter. */
  455. isdelim(char c)
  456. {
  457.   if(strchr(" !;,+-<>'/*%^=()", c) || c==9 ||
  458.      c=='\r' || c==0) return 1;  
  459.   return 0; 
  460. }
  461. /* Return 1 if c is space or tab. */
  462. iswhite(char c)
  463. {
  464.   if(c==' ' || c=='\t') return 1;
  465.   else return 0;
  466. }
  467.  
  468.  
  469. [LISTING TWO]
  470.  
  471. /* A Little C interpreter. */
  472.  
  473. #include "stdio.h"
  474. #include "setjmp.h"
  475. #include "math.h"
  476. #include "ctype.h"
  477. #include "stdlib.h"
  478. #include "string.h"
  479.  
  480. #define NUM_FUNC       100
  481. #define NUM_GLOBAL_VARS 100
  482. #define NUM_LOCAL_VARS  200
  483. #define NUM_BLOCK    100
  484. #define ID_LEN          31 
  485. #define FUNC_CALLS      31
  486. #define NUM_PARAMS    31
  487. #define PROG_SIZE     10000
  488. #define LOOP_NEST    31
  489.  
  490. enum tok_types {DELIMITER, IDENTIFIER, NUMBER, KEYWORD, 
  491.                 TEMP, STRING, BLOCK};
  492. /* add additional C keyword tokens here */
  493. enum tokens {ARG, CHAR, INT, IF, ELSE, FOR, DO, WHILE,
  494.              SWITCH, RETURN, EOL, FINISHED, END};
  495. /* add additional double operators here (such as ->) */
  496. enum double_ops {LT=1, LE, GT, GE, EQ, NE};
  497. /* These are the constants used to call sntx_err() when
  498.    a syntax error occurs.  Add more if you like.
  499.    NOTE: SYNTAX is a generic error message used when
  500.    nothing else seems appropriate.
  501. */
  502. enum error_msg 
  503.      {SYNTAX, UNBAL_PARENS, NO_EXP, EQUALS_EXPECTED,
  504.       NOT_VAR, PARAM_ERR, SEMI_EXPECTED,
  505.       UNBAL_BRACES, FUNC_UNDEF, TYPE_EXPECTED,
  506.       NEST_FUNC, RET_NOCALL, PAREN_EXPECTED,
  507.       WHILE_EXPECTED, QUOTE_EXPECTED, NOT_TEMP,
  508.       TOO_MANY_LVARS};
  509. char *prog;  /* current location in source code */
  510. char *p_buf; /* points to start of program buffer */
  511. jmp_buf e_buf; /* hold environment for longjmp() */
  512.  
  513. /* An array of these structures will hold the info
  514.    associated with global variables.
  515. */
  516. struct var_type {
  517.   char var_name[ID_LEN];
  518.   int var_type;
  519.   int value;è}  global_vars[NUM_GLOBAL_VARS];
  520. struct var_type local_var_stack[NUM_LOCAL_VARS];
  521. struct func_type {
  522.   char func_name[ID_LEN];
  523.   char *loc;  /* location of entry point in file */
  524. } func_table[NUM_FUNC];
  525. int call_stack[NUM_FUNC];
  526. struct commands { /* keyword lookup table */
  527.   char command[20];
  528.   char tok;
  529. } table[] = { /* Commands must be entered lowercase */
  530.   "if", IF, /* in this table. */
  531.   "else", ELSE,
  532.   "for", FOR,
  533.   "do", DO,
  534.   "while", WHILE,
  535.   "char", CHAR,
  536.   "int", INT,
  537.   "return", RETURN,
  538.   "end", END,
  539.   "", END  /* mark end of table */
  540. };
  541. char token[80];
  542. char token_type, tok;
  543. int functos;  /* index to top of function call stack */
  544. int func_index; /* index into function table */
  545. int gvar_index; /* index into global variable table */
  546. int lvartos; /* index into local variable stack */
  547. int ret_value; /* function return value */
  548. void print(void), prescan(void);
  549. void decl_global(void), call(void), putback(void);
  550. void decl_local(void), local_push(struct var_type i);
  551. void eval_exp(int *value), sntx_err(int error);
  552. void exec_if(void), find_eob(void), exec_for(void);
  553. void get_params(void), get_args(void);
  554. void exec_while(void), func_push(int i), exec_do(void);
  555. void assign_var(char *var_name, int value);
  556. int load_program(char *p, char *fname), find_var(char *s);
  557. void interp_block(void), func_ret(void);
  558. int func_pop(void), is_var(char *s), get_token(void);
  559. char *find_func(char *name);
  560.  
  561. main(int argc, char *argv[])
  562. {
  563.   if(argc!=2) {
  564.     printf("usage: c <filename>\n");
  565.     exit(1);è  }
  566.   /* allocate memory for the program */
  567.   if((p_buf=(char *) malloc(PROG_SIZE))==NULL) {
  568.     printf("allocation failure");
  569.     exit(1);
  570.   }
  571.   /* load the program to execute */
  572.   if(!load_program(p_buf, argv[1])) exit(1);
  573.   if(setjmp(e_buf)) exit(1); /* initialize long jump buffer */
  574.   /* set program pointer to start of program buffer */
  575.   prog = p_buf; 
  576.   prescan(); /* find the location of all functions
  577.                    and global variables in the program */
  578.   gvar_index = 0;  /* initialize global variable index */
  579.   lvartos = 0;     /* initialize local variable stack index */
  580.   functos = 0;     /* initialize the CALL stack index */
  581.   /* setup call to main() */
  582.   prog = find_func("main");  /* find program starting point */
  583.   prog--; /* back up to opening ( */
  584.   strcpy(token, "main");
  585.   call();  /* call main() to start interpreting */
  586. }
  587. /* Interpret a single statement or block of code.  When
  588.    interp_block() returns from it's initial call, the final
  589.    brace (or a return) in main() has been encountered.
  590. */
  591. void interp_block(void)
  592. {
  593.   int value;
  594.   char block = 0;
  595.   do {
  596.     token_type = get_token();
  597.     /* If interpreting single statement, return on
  598.        first semicolon.
  599.     */
  600.     /* see what kind of token is up */
  601.     if(token_type==IDENTIFIER) { 
  602.       /* Not a keyword, so process expression. */
  603.     putback();  /* restore token to input stream for
  604.                        further processing by eval_exp() */
  605.     eval_exp(&value);  /* process the expression */
  606.         if(*token!=';') sntx_err(SEMI_EXPECTED);
  607.     }
  608.     else if(token_type==BLOCK) { /* if block delimiter */
  609.       if(*token=='{') /* is a block */è        block = 1; /* interpreting block, not statement */
  610.       else return; /* is a }, so return */
  611.     }
  612.     else /* is keyword */
  613.       switch(tok) {
  614.         case CHAR:
  615.        case INT:     /* declare local variables */
  616.           putback();
  617.       decl_local();
  618.       break;
  619.     case RETURN:  /* return from function call */
  620.       func_ret();
  621.       return; 
  622.     case IF:      /* process an if statement */
  623.       exec_if();
  624.       break;
  625.     case ELSE:    /* process an else statement */
  626.       find_eob(); /* find end of else block 
  627.              and continue execution */
  628.       break;      
  629.     case WHILE:   /* process a while loop */
  630.       exec_while();
  631.       break;
  632.         case DO:      /* process a do-while loop */
  633.       exec_do();
  634.       break;
  635.     case FOR: exec_for();
  636.       break;
  637.         case END:
  638.       exit(0);
  639.       }
  640.   } while (tok != FINISHED && block);
  641. }
  642. /* Load a program. */
  643. load_program(char *p, char *fname)
  644. {
  645.   FILE *fp;
  646.   int i=0;
  647.   if((fp=fopen(fname, "rb"))==NULL) return 0;
  648.   i = 0;
  649.   do {
  650.     *p = getc(fp);
  651.     p++; i++;
  652.   } while(!feof(fp) && i<PROG_SIZE);
  653.   *(p-2) = '\0'; /* null terminate the program */
  654.   fclose(fp);
  655.   return 1;
  656. }
  657. /* Find the location of all functions in the program
  658.    and store global variables. */
  659. void prescan(void)è{
  660.   char *p;
  661.   char temp[32];
  662.   int brace = 0;  /* When 0, this var tells us that
  663.              current source position is outside
  664.                of any function. */
  665.   p = prog;
  666.   func_index = 0;
  667.   do { 
  668.     while(brace) {  /* bypass code inside functions */
  669.       get_token();
  670.       if(*token=='{') brace++;
  671.       if(*token=='}') brace--;
  672.     }
  673.     get_token();
  674.     if(tok==CHAR || tok==INT) { /* is global var */
  675.       putback();
  676.       decl_global();
  677.     }      
  678.     else if(token_type==IDENTIFIER) { 
  679.       strcpy(temp, token);
  680.       get_token();
  681.       if(*token=='(') {  /* must be assume a function */
  682.         func_table[func_index].loc = prog;
  683.         strcpy(func_table[func_index].func_name, temp);
  684.         func_index++;
  685.         while(*prog!=')') prog++;
  686.         prog++;
  687.     /* prog points to opening curly brace of function */
  688.       }
  689.       else putback();
  690.     }
  691.     else if(*token=='{') brace++;
  692.   } while(tok!=FINISHED);
  693.   prog = p;
  694. }
  695. /* Return the entry point of the specified function. 
  696.    Return NULL if not found.
  697. */
  698. char *find_func(char *name)
  699. {
  700.   register int i;
  701.   for(i=0; i<func_index; i++)
  702.     if(!strcmp(name, func_table[i].func_name))
  703.       return func_table[i].loc;
  704.   return NULL;
  705. }
  706. /* Declare a global variable. */èvoid decl_global(void)
  707. {
  708.   get_token();  /* get type */
  709.   global_vars[gvar_index].var_type = tok;
  710.   global_vars[gvar_index].value = 0;  /* init to 0 */
  711.   do { /* process comma-separated list */
  712.     get_token();  /* get name */
  713.     strcpy(global_vars[gvar_index].var_name, token);
  714.     get_token();
  715.     gvar_index++;
  716.   } while(*token==',');
  717.   if(*token!=';') sntx_err(SEMI_EXPECTED);
  718. }
  719. /* Declare a local variable. */
  720. void decl_local(void)
  721. {
  722.   struct var_type i;
  723.   get_token();  /* get type */
  724.   i.var_type = tok;
  725.   i.value = 0;  /* init to 0 */
  726.   do { /* process comma-separated list */
  727.     get_token(); /* get var name */
  728.     strcpy(i.var_name, token);
  729.     local_push(i);
  730.     get_token();
  731.   } while(*token==',');
  732.   if(*token!=';') sntx_err(SEMI_EXPECTED);
  733. }
  734. /* Call a function. */
  735. void call(void)
  736. {
  737.   char *loc, *temp;
  738.   int lvartemp;
  739.   loc = find_func(token); /* find entry point of function */
  740.   if(loc==NULL)
  741.     sntx_err(FUNC_UNDEF); /* function not defined */
  742.   else {
  743.     lvartemp = lvartos;  /* save local var stack index */
  744.     get_args();  /* get function arguments */
  745.     temp = prog; /* save return location */
  746.     func_push(lvartemp);  /* save local var stack index */
  747.     prog = loc;  /* reset prog to start of function */
  748.     get_params(); /* load the function's parameters with 
  749.              the values of the arguments */
  750.     interp_block(); /* interpret the function */
  751.     prog = temp; /* reset the program pointer */
  752.     lvartos = func_pop(); /* reset the local var stack */è  }
  753. }
  754. /* Push the arguments to a function onto the local
  755.    variable stack. */
  756. void get_args(void)
  757. {
  758.   int value, count, temp[NUM_PARAMS];
  759.   struct var_type i;
  760.   count = 0;
  761.   get_token();
  762.   if(*token!='(') sntx_err(PAREN_EXPECTED);
  763.   /* process a comma-separated list of values */
  764.   do {
  765.     eval_exp(&value);
  766.     temp[count] = value;  /* save temporarily */
  767.     get_token();
  768.     count++;
  769.   }while(*token==',');
  770.   count--;
  771.   /* now, push on local_var_stack in reverse order */
  772.   for(; count>=0; count--) {
  773.     i.value = temp[count];
  774.     i.var_type = ARG;
  775.     local_push(i);
  776.   }
  777. }
  778. /* Get function parameters. */
  779. void get_params(void)
  780. {
  781.   struct var_type *p;
  782.   int i;
  783.   i = lvartos-1;
  784.   do { /* process comma-separated list of parameters */
  785.     get_token();  
  786.     p = &local_var_stack[i];
  787.     if(*token!=')') {
  788.       if(tok!=INT && tok!=CHAR) sntx_err(TYPE_EXPECTED);
  789.       p->var_type = token_type;
  790.       get_token();
  791.       /* link parameter name with argument already on 
  792.      local var stack */
  793.       strcpy(p->var_name, token);
  794.       get_token();
  795.       i--;
  796.     }
  797.     else break;
  798.   } while(*token==',');
  799.   if(*token!=')') sntx_err(PAREN_EXPECTED); 
  800. }è/* Return from a function. */
  801. void func_ret(void)
  802. {
  803.   int value;
  804.   value = 0;
  805.   /* get return value, if any */
  806.   eval_exp(&value);
  807.   ret_value = value;
  808. }
  809. /* Push local variable */
  810. void local_push(struct var_type i)
  811. {
  812.   if(lvartos>NUM_LOCAL_VARS)
  813.    sntx_err(TOO_MANY_LVARS);
  814.   local_var_stack[lvartos] = i;
  815.   lvartos++;
  816. }
  817. /* Pop index into local variable stack. */
  818. func_pop(void)
  819. {
  820.   functos--;
  821.   if(functos<0) sntx_err(RET_NOCALL);
  822.   return(call_stack[functos]);
  823. }
  824. /* Push index of local variable stack. */
  825. void func_push(int i)
  826. {
  827.   if(functos>NUM_FUNC)
  828.    sntx_err(NEST_FUNC);
  829.   call_stack[functos] = i;
  830.   functos++;
  831. }
  832. /* Assign a value to a variable. */
  833. void assign_var(char *var_name, int value)
  834. {
  835.   register int i;
  836.   /* first, see if it's a local variable */
  837.   for(i=lvartos-1; i>=call_stack[functos-1]; i--)  {
  838.     if(!strcmp(local_var_stack[i].var_name, var_name)) {
  839.       local_var_stack[i].value = value;
  840.       return;
  841.     }
  842.   }
  843.   if(i < call_stack[functos-1]) 
  844.   /* if not local, try global var table */
  845.     for(i=0; i<NUM_GLOBAL_VARS; i++)è      if(!strcmp(global_vars[i].var_name, var_name)) {
  846.         global_vars[i].value = value;
  847.         return;
  848.       }
  849.   sntx_err(NOT_VAR); /* variable not found */
  850. }
  851. /* Find the value of a variable. */
  852. int find_var(char *s)
  853. {
  854.   register int i;
  855.   /* first, see if it's a local variable */
  856.   for(i=lvartos-1; i>=call_stack[functos-1]; i--) 
  857.     if(!strcmp(local_var_stack[i].var_name, token))
  858.       return local_var_stack[i].value;
  859.   /* otherwise, try global vars */
  860.   for(i=0; i<NUM_GLOBAL_VARS; i++)
  861.     if(!strcmp(global_vars[i].var_name, s))
  862.       return global_vars[i].value;
  863.   sntx_err(NOT_VAR); /* variable not found */
  864. }
  865. /* Determine if an identifier is a variable. Return
  866.    1 if variable is found; 0 otherwise.
  867. */
  868. int is_var(char *s)
  869. {
  870.   register int i;
  871.   /* first, see if it's a local variable */
  872.   for(i=lvartos-1; i>=call_stack[functos-1]; i--) 
  873.     if(!strcmp(local_var_stack[i].var_name, token))
  874.       return 1;
  875.   /* otherwise, try global vars */
  876.   for(i=0; i<NUM_GLOBAL_VARS; i++)
  877.     if(!strcmp(global_vars[i].var_name, s))
  878.       return 1;
  879.   return 0; 
  880. }
  881. /* Execute an IF statement. */
  882. void exec_if(void)
  883. {
  884.   int cond;
  885.   eval_exp(&cond); /* get left expression */
  886.   if(cond) { /* is true so process target of IF */
  887.     interp_block();
  888.   }è  else { /* otherwise skip around IF block and
  889.         process the ELSE, if present */
  890.     find_eob(); /* find start of next line */
  891.     get_token();
  892.     if(tok!=ELSE) {
  893.       putback();  /* restore token if
  894.                      no ELSE is present */
  895.       return;
  896.     }
  897.     interp_block();
  898.   }
  899. }
  900. /* Execute a while loop. */
  901. void exec_while(void)
  902. {
  903.   int cond;
  904.   char *temp;
  905.   putback();
  906.   temp = prog;  /* save location of top of while loop */
  907.   get_token();
  908.   eval_exp(&cond);  /* check the conditional expression */
  909.   if(cond) interp_block();  /* if true, interpret */
  910.   else {  /* otherwise, skip around loop */
  911.     find_eob();
  912.     return;
  913.   }
  914.   prog = temp;  /* loop back to top */
  915. }
  916. /*Execute a do loop. */
  917. void exec_do(void)
  918. {
  919.   int cond;
  920.   char *temp;
  921.   putback();
  922.   temp = prog;  /* save location of top of do loop */
  923.   get_token(); /* get start of loop */
  924.   interp_block(); /* interpret loop */
  925.   get_token(); 
  926.   if(tok!=WHILE) sntx_err(WHILE_EXPECTED);
  927.   eval_exp(&cond); /* check the loop condition */
  928.   if(cond) prog = temp; /* if true loop; otherwise, 
  929.                            continue on */
  930. }
  931. /* Find the end of a block. */
  932. void find_eob(void)
  933. {
  934.   int brace;
  935.   get_token();
  936.   brace = 1;
  937.   do {
  938.     get_token();
  939.     if(*token=='{') brace++;
  940.     else if(*token=='}') brace--;
  941.   } while(brace);
  942. }
  943. /* Execute a while loop. */
  944. void exec_for(void)
  945. {
  946.   int cond;
  947.   char *temp, *temp2;
  948.   int brace ;
  949.   get_token();
  950.   eval_exp(&cond);  /*initialization expression */
  951.   if(*token!=';') sntx_err(SEMI_EXPECTED);
  952.   prog++; /* get past the ; */
  953.   temp = prog;
  954.   for(;;) {
  955.     eval_exp(&cond);  /* check the condition */    
  956.     if(*token!=';') sntx_err(SEMI_EXPECTED);
  957.     prog++; /* get past the ; */
  958.     temp2 = prog;
  959.     /* find the start of the for block */
  960.     brace = 1;
  961.     while(brace) {
  962.       get_token();
  963.       if(*token=='(') brace++;
  964.       if(*token==')') brace--;
  965.     }
  966.     if(cond) interp_block();  /* if true, interpret */
  967.     else {  /* otherwise, skip around loop */
  968.       find_eob();
  969.       return;
  970.     }
  971.     prog = temp2;
  972.     eval_exp(&cond); /* do the increment */
  973.     prog = temp;  /* loop back to top */
  974.   } 
  975. }
  976.  
  977.  
  978. [LISTING THREE]
  979.  
  980. /****** Internal Library Functions *******/
  981.  
  982. /* Add more of your own, here. */
  983.  
  984. #include "conio.h"  /* if your compiler does not 
  985.                        support this  header file, 
  986.                        remove it */
  987. #include "stdio.h"
  988. #include "stdlib.h"
  989.  
  990. extern char *prog; /* points to current location in program */
  991. extern char token[80]; /* holds string representation of token */
  992. extern char token_type; /* contains type of token */
  993. extern char tok; /* holds the internal representation of token */
  994.  
  995. enum tok_types {DELIMITER, IDENTIFIER, NUMBER, COMMAND, STRING,
  996.             QUOTE, VARIABLE, BLOCK, FUNCTION};
  997. /* These are the constants used to call sntx_err() when
  998.    a syntax error occurs.  Add more if you like.
  999.    NOTE: SYNTAX is a generic error message used when
  1000.    nothing else seems appropriate.
  1001. */
  1002. enum error_msg 
  1003.      {SYNTAX, UNBAL_PARENS, NO_EXP, EQUALS_EXPECTED,
  1004.       NOT_VAR, PARAM_ERR, SEMI_EXPECTED,
  1005.       UNBAL_BRACES, FUNC_UNDEF, TYPE_EXPECTED,
  1006.       NEST_FUNC, RET_NOCALL, PAREN_EXPECTED,
  1007.       WHILE_EXPECTED, QUOTE_EXPECTED, NOT_STRING,
  1008.       TOO_MANY_LVARS};
  1009. int get_token(void);
  1010. void sntx_err(int error), eval_exp(int *result);
  1011. void putback(void);
  1012. /* Get a character from console.  (Use getchar()) if
  1013.    your compiler does not support getche().) */
  1014. call_getche()
  1015. {
  1016.   char ch;
  1017.   ch = getche();
  1018.   while(*prog!=')') prog++;
  1019.   prog++;   /* advance to end of line */
  1020.   return ch;
  1021. }
  1022. /* Put a character to the display.  (Use putchar()
  1023.    if your compiler does not support putch().) */
  1024. call_putch()
  1025. {
  1026.   int value;
  1027.   eval_exp(&value);
  1028.   printf("%c", value);
  1029.   return value;
  1030. }
  1031. /* Call puts(). */
  1032. call_puts(void)
  1033. {
  1034.   get_token();è  if(*token!='(') sntx_err(PAREN_EXPECTED);
  1035.   get_token();
  1036.   if(token_type!=QUOTE) sntx_err(QUOTE_EXPECTED);
  1037.   puts(token);
  1038.   get_token();
  1039.   if(*token!=')') sntx_err(PAREN_EXPECTED);
  1040.   get_token();
  1041.   if(*token!=';') sntx_err(SEMI_EXPECTED);
  1042.   putback();
  1043.   return 0;
  1044. }
  1045. /* A built-in console output function. */
  1046. int print(void)
  1047. {
  1048.   int i;
  1049.   get_token();
  1050.   if(*token!='(')  sntx_err(PAREN_EXPECTED);
  1051.   get_token();
  1052.   if(token_type==QUOTE) { /* output a string */
  1053.     printf("%s ", token);
  1054.   }
  1055.   else {  /* output a number */
  1056.    putback();
  1057.    eval_exp(&i);   
  1058.    printf("%d ", i);
  1059.   }
  1060.   get_token();
  1061.   if(*token!=')') sntx_err(PAREN_EXPECTED);
  1062.   get_token();
  1063.   if(*token!=';') sntx_err(SEMI_EXPECTED);
  1064.   putback();
  1065.   return 0;
  1066. }
  1067. /* Read an integer from the keyboard. */
  1068. getnum(void)
  1069. {
  1070.   char s[80];
  1071.   gets(s);
  1072.   while(*prog!=')') prog++;
  1073.   prog++;  /* advance to end of line */
  1074.   return atoi(s);
  1075. }
  1076.  
  1077. [LISTING FOUR]
  1078.  
  1079. /* C Interpreter Demonstration Program 
  1080.    This program demonstrates all features
  1081.    of C that are recognized by this C interpreter.
  1082. */
  1083. int i, j;   /* global vars */
  1084. char ch;
  1085.  
  1086. main()
  1087. {  
  1088.   int i, j;  /* local vars */
  1089.   puts("C Demo Program.");
  1090.   print_alpha();
  1091.   do {
  1092.     puts("enter a number (0 to quit): ");
  1093.     i = getnum();
  1094.     if(i < 0 ) {
  1095.       puts("numbers must be positive, try again");
  1096.     }
  1097.     else {
  1098.       for(j = 0; j < i; j=j+1) {
  1099.         print(j);
  1100.         print("summed is");
  1101.         print(sum(j));
  1102.         puts("");
  1103.       }
  1104.     }
  1105.   } while(i!=0);
  1106. }
  1107. /* Sum the values between 0 and num. */
  1108. sum(int num)
  1109. {
  1110.   int running_sum;
  1111.   running_sum = 0;
  1112.   while(num) {
  1113.     running_sum = running_sum + num;
  1114.     num = num - 1;
  1115.   }
  1116.   return running_sum;
  1117. }
  1118. /* Print the alphabet. */
  1119. print_alpha()
  1120. {
  1121.   for(ch = 'A'; ch<='Z'; ch = ch + 1) {
  1122.     putch(ch);
  1123.   }
  1124.   puts("");
  1125. }
  1126. /* Nested loop example. */
  1127. main()
  1128. {
  1129.   int i, j, k;
  1130.   for(i = 0; i < 5; i = i + 1) {
  1131.     for(j = 0; j < 3; j = j + 1) { è      for(k = 3; k ; k = k - 1) {
  1132.         print(i);
  1133.         print(j);
  1134.         print(k);
  1135.         puts("");
  1136.       }
  1137.     }
  1138.   }
  1139.   puts("done");    
  1140. }
  1141. /* Assigments as operations. */
  1142. main()
  1143. {
  1144.   int a, b;
  1145.   a = b = 10;
  1146.   print(a); print(b);
  1147.   while(a=a-1) {
  1148.     print(a);
  1149.     do {
  1150.        print(b); 
  1151.     }while((b=b-1) > -10); 
  1152.   }
  1153. }
  1154. /* This program demonstrates recursive functions. */
  1155. main()
  1156. {
  1157.  print(factr(7) * 2);
  1158. }
  1159. /* return the factorial of i */
  1160. factr(int i)
  1161. {
  1162.   if(i<2) {
  1163.     return 1;
  1164.   }
  1165.   else {
  1166.     return i * factr(i-1);
  1167.   }
  1168. }
  1169. /* A more rigorous example of function arguments. */
  1170. main()
  1171. {
  1172.   f2(10, f1(10, 20), 99);
  1173. }
  1174. f1(int a, int b)
  1175. {
  1176.   int count;
  1177.   print("in f1");
  1178.   count = a;
  1179.   do {
  1180.     print(count); 
  1181.   } while(count=count-1);
  1182.   print(a); print(b);
  1183.   print(a*b);
  1184.   return a*b;
  1185. }èf2(int a, int x, int y)
  1186. {
  1187.   print(a); print(x);
  1188.   print(x / a);
  1189.   print(y*x);
  1190. }
  1191. /* The loop statements. */
  1192. main()
  1193. {
  1194.   int a;
  1195.   char ch;
  1196.   /* the while */
  1197.   puts("Enter a number: ");
  1198.   a = getnum();
  1199.   while(a) {
  1200.     print(a);
  1201.     print(a*a);
  1202.     puts("");
  1203.     a = a - 1;
  1204.   }
  1205.   /* the do-while */
  1206.   puts("enter characters, 'q' to quit");
  1207.   do {
  1208.     ch = getche();
  1209.   } while(ch!='q');
  1210.   /* the for */
  1211.   for(a=0; a<10; a = a + 1) {
  1212.     print(a);
  1213.   }
  1214. }
  1215.  
  1216.   
  1217.