您的位置:首页 > 编程语言

关于Basic程序解释器及编译原理的简单化(1)---Basic器的语法分析及主要代码

2005-11-30 04:05 831 查看
关于Basic程序解释器及编译原理的简单化(1)---Basic器的语法分析及主要代码这就是Basic解释器的主代码,其中用到上节讲的词法提取get_token()和代数式求值get_exp(int *result)函数.
这一节的代码更简单,就是随心所欲地将得到的token组装.
譬如在get_token后如果token装PRINT,你就调用一次get_token将下一个token答应出来就是了,很简单的,或许你自己也能搞定的.
在下一节你,我会给你完整的C++封装好了的源代码.
/*  A tiny BASIC interpreter  */
#include <stdio.h>
#include <setjmp.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#define NUM_LAB 100
#define LAB_LEN 10
#define FOR_NEST 25
#define SUB_NEST 25
#define PROG_SIZE 10000
#define DELIMITER 1
#define VARIABLE 2
#define NUMBER 3
#define COMMAND 4
#define STRING 5
#define QUOTE 6
#define PRINT 1
#define INPUT 2
#define IF 3
#define THEN 4
#define FOR 5
#define NEXT 6
#define TO 7
#define GOTO 8
#define EOL 9
#define FINISHED 10
#define GOSUB 11
#define RETURN 12
#define END 13
char *prog;      /* holds expression to be analyzed  */
jmp_buf e_buf;   /* hold environment for longjmp() */
int variables[26]= {  /* 26 user variables,A-Z  */
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0
};
struct commands { /* keyword lookup table  */
    char command[20];
    char tok;
} table[] = {  /* command must be entered lowercase  */
    "print",PRINT,   /* in this table  */
    "input",INPUT,
    "if",IF,
    "then",THEN,
    "goto",GOTO,
    "for",FOR,
    "next",NEXT,
    "to",TO,
    "gosub",GOSUB,
    "return",RETURN,
    "end",END,
    NULL,END
};
char token[80];
char token_type,tok;
struct label {
    char name [LAB_LEN];
    char *p;    /* point to place to go in source */
};
struct label label_table[NUM_LAB];
char *find_label(),*gpop();
struct for_stack {
    int var;   /* counter variable  */
    int target;  /* target value  */
    char *loc;
} fstack[FOR_NEST];  /* stack for FOR/NEXT loop  */
struct for_stack fpop();
char *gstack[SUB_NEST];  /* stack for gosub  */
int ftos;  /* index to top of FOR stack  */
int gtos;  /* index to top of GOSUB  */
void print(),scan_labels(),find_eol(),exec_goto();
void gosub(),greturn(),gpush(),label_init(),fpush();
/* Load a program */
load_program (char *p,char *fname)
{
    FILE *fp;
    int i=0;
   
    if (!(fp=fopen(fname,"rb")))  return 0;
    i=0;
    do  {
        *p = getc(fp);
        p++;i++;
    } while (!feof(fp)&&i<PROG_SIZE);
    *(p-2) = '/0';   /* null terminate the program  */
    fclose (fp);
    return 1;
}

/* assign a variable a value */
assignment()
{
    int var,value;
    /* getthe variable name */
    get_token();
    if (!isalpha(*token))  {
        serror(4);
        return;
    }
    var = toupper(*token)-'A';
    /* get the equals sign */
    get_token();
    if (*token!='=')  {
        serror(3);
        return;
    }
    /* get the value to assign to var */
    get_exp(&value);
   
    /* assign the value */
    variables[var] = value;
}

/* execute a simple version of the BASIC PRINT statement */
void print()
{
    int answer;
    int len=0,spaces;
    char last_delim;
   
    do  {
        get_token();  /* get next list item */
        if (tok==EOL||tok==FINISHED)  break;
        if (token_type==QUOTE)  {  /* is string  */
            printf ("%s",token);
            len+=strlen(token);
            get_token();
        }
        else  {  /* is expression  */
            putback();
            get_exp(&answer);
            get_token();
            len += printf ("%d",answer);
        }
        last_delim = *token;
        if (*token==',')  {
            /* compute number of move to next tab */
            spaces = 8-(len%8);
            len += spaces;  /* add in the tabbing position */
            while (spaces)  {
                printf (" ");
                spaces--;
            }
        }
        else if (*token==';')  {
            printf ("  ");
        }
        else if (tok != EOL && tok != FINISHED) serror (0);
    } while (*token==';'||*token==',');
    if (tok==EOL||tok==FINISHED)  {
        if (last_delim != ';' && last_delim != ',') printf ("/n");
    }
    else serror(0);  /* error is not, or ; */
}

/* find all labels */
void scan_labels()
{
    int addr;
    char *temp;
    label_init();  /* zero all labels */
    temp = prog;  /* save poiter to top of program */
    /* if the first token in the fike is a label */
    get_token();
    if (token_type==NUMBER)  {
        strcpy (label_table[0].name,token);
        label_table[0].p=prog;
    }
   
    find_eol();
    do  {
        get_token();
        if (token_type==NUMBER)  {
            addr = get_next_label(token);
            if (addr==-1||addr==-2)  {
                (addr==-1) ? serror(5):serror(6);
            }
            strcpy (label_table[addr].name,token);
            label_table[addr].p = prog;  /* current point in program */
        }
        /* if not on a blank line , find next line */
        if (tok!=EOL) find_eol();
    } while (tok!=FINISHED);
    prog = temp;  /* restore to original */
}

/* find the start of next line */
void find_eol()
{
    while (*prog!='/n'&&*prog!='/0')  ++prog;
    if (*prog)  prog++;
}

/* return index of next free posion in the label array
      -1 is returned if the array is full.
      -2 is returned when duplicate label is found.
*/
get_next_label(char *s)
{
    register int t;
    for (t=0;t<NUM_LAB;++t) {
        if (label_table[t].name[0]==0)  return t;
        if (!strcmp(label_table[t].name,s)) return -2;  /* dup */
    }
    return -1;
}
/* find location of given label. A null is returned if
   label is not found; ohtherwise a pointer to the position
   of the label is returned.
*/
char *find_label(char *s)
{
    register int t;
    for (t=0;t<NUM_LAB;++t)
        if (!strcmp(label_table[t].name,s))  return label_table[t].p;
    return '/0';  /* error condition */
}

/* execute a GOTO statement. */
void exec_goto()
{
    char *loc;
    get_token();  /* get label to go to */
    /* find the location of label */
    loc = find_label (token);
    if (loc=='/0')
        serror(7);  /* label not defined */
    else prog=loc;  /* start program running at that time */
}

/* initialize the array that holds the labels.
   by convention , a null label name indicates that
   array posiiton is unused.
*/
void label_init()
{
    register int t;
    for (t=0;t<NUM_LAB;++t)  label_table[t].name[0]='/0';
}

/* execute an IF statement */
void exec_if()
{
    int x,y,cond;
    char op;
    get_exp(&x);  /* get left exapression */
    get_token();  /* get the operator */
    if (!strcmp("<>",*token)) {
        serror(0);  /* not a leagal oprator */
        return;
    }
    op = *token;
    get_exp(&y);  /* get right expression */
    /* determine the outcome */
    cond = 0;
    switch(op)  {
        case '<':
            if (x<y) cond=1;
            break;
        case '>':
            if (x>y) cond=1;
            break;
        case '==':
            if (x==y) cond=1;
            break;
    }
    if (cond)  {  /* is true so process target of IF */
        get_token();
        if (tok != THEN)  {
            serror(8);
            return;
        }  /* else program execution starts on next line */
    }
    else find_eol();  /* find start of next line */
}

/* execute a FOR loop */
void exec_for()
{
    struct for_stack i;
    int value;
    get_token();  /* read the control variable */
    if (!isalpha(*token))  {
        serror(4);
        return;
    }
    i.var = toupper(*token) - 'A';  /* save its index */
    get_token();  /* read the equal sign */
    if (*token!='=')  {
        serror(3);
        return;
    }
    get_exp(&value);  /* get initial value */
    variables[i.var]=value;
    get_token();
    if (tok != TO) serror(9);  /* read an discard the TO */
    get_exp(&i.target);  /* get target value */
    /* if loop can execute at least once, push into on stack */
    if (value<=i.target)  {
        i.loc = prog;
        fpush(i);
    }
    else  /* otherwise, skip loop code altogether */
        while (tok!=NEXT)  get_token();
}

/* execute a NEXT statement */
void next()
{
    struct for_stack i;
    i = fpop();  /*read the loop info */
    variables[i.var]++;  /* increment control variable */
    if (variables[i.var]>i.target)  return;  /* all done */
    fpush(i);   /* otherwise,return the info */
    prog = i.loc;  /* loop */
}

/* push function for the FOR stack */
void fpush(struct for_stack i)
{
    if (ftos>FOR_NEST)
    serror(10);
    fstack[ftos]=i;
    ftos++;
}

struct for_stack fpop()
{
    ftos--;
    if (ftos<0)  serror(11);
    return (fstack[ftos]);
}

/* exec a simple form of BASIC INPUT command */
void input()
{
    char str[80],var;
    int i;
    get_token();  /* see if prompt string id=s present */
    if (token_type == QUOTE)  {
        printf (token);  /* if so , print it and check for command */
        get_token();
        if (*token != ',')  serror(1);
        get_token();
    }
    else printf ("? ");  /* otherwise, prompt with / */
    var = toupper(*token) - 'A';  /* get the input var */
    scanf ("%d",&i);  /* read input */
    variables[var] = i;  /* store it */
}

/* execute a GOSUB command */
void gosub()
{
    char *loc;
    get_token();
    /* find the label to call */
    loc = find_label(token);
    if (loc=='/0')
        serror(7);  /* label not defined */
    else  {
        gpush(prog);  /* save place to return to */
        prog = loc;  /* start program running at that loc */
    }
}

/* return from GOSUB */
void greturn()
{
    prog = gpop();
}

/* GOSUB stack push function */
void gpush(char *s)
{
    gtos++;
    if (gtos==SUB_NEST)  {
        serror(12);
        return;
    }
    gstack[gtos] = s;
}

/* GOSUB stack pop function */
char *gpop()
{
    if (gtos==0)  {
        serror(13);
        return 0;
    }
    return gstack[gtos--];
}
main (int argc,char *argv[])
{
    char in[80];
    int answer;
    char *p_buf;
    char *t;
    if (argc!=2)  {
        printf ("usage: run <filename>/n");
        exit (1);
    }
    /* allocate memory for the program */
    if (!(p_buf=(char *)malloc(PROG_SIZE)))  {
        printf ("allocation failure");
        exit (1);
    }
    /* load the program to execute */
    if (!load_program(p_buf,argv[1]))  exit(1);
    if (setjmp(e_buf))  exit(1); /* initialize the long jump */
    prog = p_buf;
    scan_labels();  /* find the labels in the program  */
    ftos = 0;  /* initialize the FOR stack index  */
    gtos = 0;  /* initialize the GOSUB stack index */
    do  {
        token_type = get_token();
        /* check for assignment stack */
        if (token_type==VARIABLE)  {
            putback();  /* return the varto the input stream */
            assignment();  /* must 1: assignment statemnet  */
        }
        else  /* is command */
            switch (tok)  {
                case PRINT:
                    print();
                    break;
                case GOTO:
                    exec_goto();
                    break;
                case IF:
                    exec_if();
                    break;
                case FOR:
                    exec_for();
                    break;
                case NEXT:
                    next();
                    break;
                case INPUT:
                    input();
                    break;
                case GOSUB:
                    gosub();
                    break;
                case RETURN:
                    greturn();
                    break;
                case END:
                    exit(0);
            }
    }while (tok != FINISHED);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐