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

    技术2022-05-11  159

    这就是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);}


    最新回复(0)