C语言的解释器(2)——littlec.c

longqzh posted @ 2010年7月07日 00:15 in Little C Interpreter with tags 解释器 c C语言解释器 , 2978 阅读

这就是简易的C解释器的主程序代码,可正确编译。

gcc littlec.c parser.o lclib.o

clang littlec.c parser.o lclib.o

//
//  littlec.c
//  cinterp
//
//  Created by long on 12. 6. 16..
//  Copyright 2012 __MyCompanyName__. All rights reserved.
//

#include <stdio.h>
#include <setjmp.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#define NUM_FUNC        100
#define NUM_GLOBAL_VARS 100
#define NUM_LOCAL_VARS  200
#define NUM_BLOCK       100
#define ID_LEN          31
#define FUNC_CALLS      31
#define NUM_PARAMS      31
#define PROG_SIZE       10000
#define LOOP_NEST       31

enum tok_types {
    DELIMITER, IDENTIFIER, NUMBER, KEYWORD,
    TEMP, STRING, BLOCK
};

/* add additional C keyword tokens here */
enum tokens{
    ARG, CHAR, INT, IF, ELSE, FOR, DO, WHILE,
    SWITCH, RETURN, EOL, FINISHED, END
};

/* add additional double operators here */
enum double_ops{LT=1, LE, GT, GE, EQ, NE};


/*  These are the constants used to call sntx_err() when
 a syntax error occurs. Add more if you like.
 
 NOTE: SYNTAX is a generic error message used when 
 nothing 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_EXPECED, QUOTE_EXPECTED, NOT_TEMP,
    TOO_MANY_LVARS
};

char *prog;  /* current location in source code */
char *p_buf; /* points to start of program buffer */
jmp_buf e_buf;   /* hold environment for longjmp() */


/*  An array of these structures will hold the info
 associated with global variables.
 */
struct var_type{
    char var_name[ID_LEN];
    int var_type;
    int value;
}  global_vars[NUM_GLOBAL_VARS];

struct var_type local_var_stack[NUM_LOCAL_VARS];

/* This is the function call stack */
struct func_type{
    char func_name[ID_LEN];
    char *loc;        /* location of function entry point in file */
} func_table[NUM_FUNC];

int call_stack[NUM_FUNC];

/* Keyword lookup table */
struct commands{
    char command[20];
    char tok;
}table[]={  /* Commands must be entered lowercase */
    "if",IF,
    "else",ELSE,
    "for",FOR,
    "do",DO,
    "while",WHILE,
    "char",CHAR,
    "int",INT,
    "return",RETURN,
    
    "end",END,
    "",END
};

char token[80];
char token_type,tok;

int functos;    /* index to top of function call stack */
int func_index; /* index into function table */
int gvar_index; /* index into global variable table */
int lvartos;    /* index into  local variable stack */

int ret_value;  /* function return value */

void print();
void prescan();
void decl_global(),decl_local();
void call();
void putback();
void local_push(struct var_type i);
void eval_exp(int *value);
void sntx_err(int error);
void get_params();
void get_args();
void exec_if();
void exec_for();
void exec_do();
void exec_while();
void find_eob();
void func_push(int i);
void assign_var(char *var_name, int value);
void interp_block();
void func_ret();

int load_program(char *p,char *fname);
int find_var(char *s);
int func_pop();
int is_var(char *s);
int get_token();

char *find_func(char *name);

int main(int argc, char *argv[])
{
    if(argc!=2){
        printf ("usage: littlec <filename>\n");
        exit(1);
    }
    
    /* allocate memory for the program */
    if((p_buf=(char *) malloc(PROG_SIZE))==NULL){
        printf("allocation failure");
        exit(1);
    }
    
    /* load the program to execute */
    if( !load_program(p_buf,argv[1]))
        exit(1);
    if(setjmp(e_buf))   /* initialize long jump buffer */
        exit(1);
    
    /* set program pointer to start of the program buffer */
    prog=p_buf;
    prescan();  /* find the location of all function
                and global variables in the program */
    
    gvar_index=0;   /* initialize global variable index */
    lvartos=0;      /* initialize local variable stack index */
    functos=0;      /* initialize the CALL stack index */
    
    /* setup call to main() */
    prog=find_func("main");
    prog--;         /* abck up to opening ( */
    strcpy(token,"main");
    call();         /* call main() to start interpreting */
}

void interp_block()
{
    int value;
    char block=0;
    
    do{
        token_type=get_token();
        
        /*  If interpreting single statement, return
            on first semicolon.
         */
        
        /* see what kind of token is up */
        if(token_type==IDENTIFIER){
            /* Not a keyword, so process expression */
            putback();  /* restore token to input stream for
                         further processing by eval_exp() */
            eval_exp(&value);   /* process the expression */
            
            if (*token!=';') 
                sntx_err(SEMI_EXPECTED);
            else if(token_type==BLOCK){
                if(*token=='{')
                    block=1;    /* interpreting block, not statement */
                else return;    /* is a },so return */
            }
            else    /* is keyword */
                switch(tok){
                    case CHAR:
                    case INT:
                        putback();
                        decl_local();
                        break;
                    case RETURN:
                        func_ret();
                        return;
                    case IF:
                        exec_if();
                        break;
                    case ELSE:
                        /* find end of else block
                         and continue execution */
                        find_eob();
                        break;
                    case WHILE:
                        exec_while();
                        break;
                    case DO:
                        exec_do();
                        break;
                    case FOR:
                        exec_for();
                        break;
                    case END:
                        exit(0);
                }
        }
    } while(tok != FINISHED && block);
}
    
/* load a program. */
int load_program(char *p,char *fname)
{
    FILE *fp;
    int i=0;
        
    if((fp=fopen(fname,"rb"))==NULL)
        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;
}

/*  Find the location of all functions in the program
    and store global variables
 */
void prescan()
{
    char *p;
    char temp[32];
    int brace=0;    /*  when 0, this var tells us that
                        current source position is outside
                        of any function.
                     */
    p=prog;
    func_index=0;
    do{
        while(brace){
            get_token();
            if(*token=='{') brace++;
            if(*token=='}') brace--;
        }
        
        get_token();
        
        if(tok==CHAR || tok==INT){  /* is global var */
            putback();
            decl_global();
        }
        else if(token_type==IDENTIFIER){
            strcpy(temp,token);
            get_token();
            if(*token=='('){    /* must be assume a function */
                func_table[func_index].loc=prog;
                strcpy(func_table[func_index].func_name,temp);
                func_index++;
                while( *prog!= ')') prog++;
                prog++;
                /* prog points to opening curly brace of function */
            }
            else putback();
        }
        else if (*token=='{')
            brace++;
    } while(tok!=FINISHED);
        prog=p;
}

/*  Return the entry point of the specified function.
    Return NULL if not found
 */
char *find_func(char *name)
{
    register int i;
    
    for(i=0;i<func_index;i++)
        if(!strcmp(name,func_table[i].func_name))
            return func_table[i].loc;
    
    return NULL;
}

/* Declare a global variable */
void decl_global()
{
    get_token();
    
    global_vars[gvar_index].var_type=tok;
    global_vars[gvar_index].value=0;
    
    do{    /* process comma-separated list */
        get_token();    /* get name */
        strcpy(global_vars[gvar_index].var_name,token);
        get_token();
        gvar_index++;
    } while (*token != ';');
    if(*token!=';')
        sntx_err(SEMI_EXPECTED);
}

/* Declare a local variable. */
void decl_local()
{
    struct var_type i;
    get_token();
    
    i.var_type=tok;
    i.value=0;
    
    do{
        get_token();
        strcpy(i.var_name,token);
        local_push(i);
        get_token();
    } while (*token==',');
    if(*token!=';')
        sntx_err(SEMI_EXPECTED);
}

/* Call a function */
void call()
{
    char *loc,*temp;
    int lvartemp;
    
    loc=find_func(token);
    if(loc==NULL)
        sntx_err(FUNC_UNDEF);
    else{
        lvartemp=lvartos;   /* save local var stack index */
        get_args();
        temp=prog;  /* save return location */
        func_push(lvartemp);
        prog=loc;   /* reset prog to start of function */
        get_params();
        interp_block();
        prog=temp;  /* reset the program pointer */
        lvartos=func_pop();
    }
}

/*  Push the arguments to a function onto the local
    variable stack
 */
void get_args()
{
    int value,count,temp[NUM_PARAMS];
    struct var_type i;
    
    count=0;
    get_token();
    if(*token!='(')
        sntx_err(PAREN_EXPECTED);
    
    /* process a comma-separated list of values */
    do{
        eval_exp(&value);
        temp[count]=value; /* save temporarily */
        get_token();
        count++;
    } while (*token==',');
    count--;
    
    /* now, push on local_var_stack in reverse order */
    for(;count>=0;count--){
        i.value=temp[count];
        i.var_type=ARG;
        local_push(i);
    }
}

/* Get function parameters */
void get_params()
{
    struct var_type *p;
    int i;
    
    i=lvartos-1;
    do{
        get_token();
        p=&local_var_stack[i];
        
        if(*token!=')'){
            if(tok!=INT && tok!=CHAR)
                sntx_err(TYPE_EXPECTED);
            p->var_type=token_type;
            get_token();
            
            /*  link parameter name with argument 
                alreadyb on local var stack
             */
            strcpy(p->var_name,token);
            get_token();
            i--;
        }
        else break;
    } while(*token!=')');
    if(*token!=')')
        sntx_err(PAREN_EXPECTED);
}

/* Return from a function */
void func_ret()
{
    int value=0;
    
    /* get return value, if any */
    eval_exp(&value);
    
    ret_value=value;
}
           

/* Push local variable */
void local_push(struct var_type i)
{
    if(lvartos>NUM_LOCAL_VARS)
        sntx_err(TOO_MANY_LVARS);

    local_var_stack[lvartos]=i;
    lvartos++;
}

/* Pop index into local variable stack */
int func_pop()
{
    functos--;
    if(functos<0) 
        sntx_err(RET_NOCALL);
    return (call_stack[functos]);
            
}
                 
/* Push index of local variable stack */
void func_push(int i)
{
    if(functos > NUM_FUNC)
        sntx_err(NEST_FUNC);
    call_stack[functos]=i;
    
    functos++;
}
                 

/* Assign a value to a variable */
void assign_var(char *var_name, int value)
{
    register int i;
    
    /* first, see if it's a local variable */
    for(i=lvartos-1;i>= call_stack[functos-1];i--);{
        if(!strcmp(local_var_stack[i].var_name,var_name)){
            local_var_stack[i].value=value;
            return;
        }
    }
    if(i<call_stack[functos-1])
        /* if not local, try global var table */
        for (i=0;i < NUM_GLOBAL_VARS;i++)
            if(!strcmp(global_vars[i].var_name,var_name)){
                global_vars[i].value=value;
                return;
            }
    sntx_err(NOT_VAR);
}


/*  Find the value of a variable */
int find_var(char *s)
{
    register int i;
    
    /* first, see if it's a local variable */
    for(i=lvartos-1;i>= call_stack[functos-1];i--)
        if(!strcmp(local_var_stack[i].var_name,token))
            return local_var_stack[i].value;
            
       
    /* otherwise, try global vars */
    for (i=0;i < NUM_GLOBAL_VARS;i++)
        if(!strcmp(global_vars[i].var_name,s))
            return global_vars[i].value;
    
    sntx_err(NOT_VAR);
    return -1;
}


/*  Determine if an identifier is variable.
    Return 1 if var is found;o otherwise
 */
int is_var(char *s)
{
    register int i;
    
    /* first, see if it's a local variable */
    for(i=lvartos-1;i>= call_stack[functos-1];i--)
        if(!strcmp(local_var_stack[i].var_name,token))
            return 1;
    
    
    /* otherwise, try global vars */
    for (i=0;i < NUM_GLOBAL_VARS;i++)
        if(!strcmp(global_vars[i].var_name,s))
            return 1;
    
    return 0;
}

/*  Execute an IF statement */
void exec_if()
{
    int cound;
    
    eval_exp(&cound);   /* get left expression */
    
    if(cound){
        interp_block();
    }
    else{
        find_eob();
        get_token();
        if(tok!=ELSE){
            putback();
            return;
        }
        interp_block();
    }
}

/*  Execute a while loop */
void exec_while()
{
    int cound;
    char *temp;
    
    putback();
    temp=prog;  /* save location of top of while loop */
    
    get_token();
    eval_exp(&cound);   /* check the conditional expression */
    if(cound)
        interp_block();
    else{               /* skip around loop */
        find_eob();
        return;
    }
    prog=temp;          /* loop back to top */
}


/*  Execute a Do loop */
void exec_do()
{
    int cound;
    char *temp;
    
    putback();
    temp=prog;
    
    get_token();
    interp_block();
    get_token();
    if(tok!=WHILE) 
        sntx_err(WHILE_EXPECED);
    eval_exp(&cound);
    
    if(cound)       
        /* if tru loop; otherwise, continue on */
        prog=temp; 
}

/*  Find the end of a block */
void find_eob()
{
    int brace;
    
    get_token();
    brace=1;
    do {
        get_token();
        if(*token=='{')
            brace++;
        else if (*token=='}')
            brace--;
    } while(brace);
}

/*  Execute a for loop */
void exec_for()
{
    int cound;
    char *temp,*temp2;
    int brace;
    
    get_token();
    eval_exp(&cound);   /* initialization expression */
    if(*token!=';')
        sntx_err(SEMI_EXPECTED);
    prog++; /* get past hte ; */
    temp=prog;
    
    for(;;){
        eval_exp(&cound);   /* check the condition */
        if (*token!=';')
            sntx_err(SEMI_EXPECTED);
        prog++;
        temp2=prog;
        
        /* find the start of the block */
        brace=1;
        while(brace){
            get_token();
            if(*token=='(')
                brace++;
            if(*token==')')
                brace--;
        }
        
        if(cound) interp_block();
        else{
            find_eob();
            return;
        }
        prog=temp2;
        eval_exp(&cound);
        prog=temp;
    }
}

Avatar_small
fmshcs 说:
2010年8月07日 01:37

楼主好强大~

Avatar_small
abba 说:
2010年8月07日 01:55

楼主的解释器能用吗?

Avatar_small
longqzh 说:
2010年9月10日 03:24

@abba: 除Parser.c有处定义错误之外,其他代码皆可正常编译。

Avatar_small
NCERT Term 1 Sample 说:
2022年9月27日 14:35

Candidates who to know the examination pattern or question paper style and want topic wise important questions for all subjects, NCERT Term 1 Sample Paper Class 10 with those candidates in mind here we supplied the NCERT Term-1 Sample Paper 2023 Class 10 for Session exams of SA, FA and Assignments of all subjects and languages as per the newly revised syllabus & curriculum. Candidates who to know the examination pattern or question paper style and want topic wise important questions for all subjects.Candidates who to know the examination pattern or question paper style and want topic wise important questions for all subjects

Avatar_small
civaget 说:
2023年12月09日 22:28

Hot stone therapy at a 스파 is pure indulgence. The ultimate relaxation awaits!

Avatar_small
civaget 说:
2023年12月10日 00:36

My EPL journey is incomplete without epl무료중계, providing real-time scores and in-depth insights.

Avatar_small
civaget 说:
2023年12月10日 04:46

When it comes to 구글 seo, the speed at which your pages load can be the difference between a bounce and a conversion.

Avatar_small
civaget 说:
2023年12月11日 22:50

A tranquil escape at 대부도펜션! The pool villa complex is a paradise on Daebudo Island.

Avatar_small
civaget 说:
2023年12月17日 21:31

청주오피 is a lifesaver for finding relaxation spots in Cheongju. Transparent pricing and user reviews make decision-making a breeze.

Avatar_small
civaget 说:
2023年12月18日 22:15

밤떡 is a game-changer for local businesses, connecting them with their communities like never before.

Avatar_small
civaget 说:
2023年12月26日 22:29

I can't praise 부달 enough for its exceptional Gyeongnam coverage. Its articles are informative, engaging, and truly enriching for travelers.

Avatar_small
civaget 说:
2023年12月26日 22:39

오피타임's commitment to quality is commendable.

Avatar_small
civaget 说:
2023年12月28日 22:58

Ulsan 울산오피 is a must-visit for massage lovers.

Avatar_small
civaget 说:
2024年1月01日 22:44

Finding massage parlors nearby is a breeze with 오피스타. It's a game-changer.

Avatar_small
civaget 说:
2024年1月06日 23:16

The crystal-clear streaming on 누누tv elevates my viewing experience. It's like having a theater at home.

Avatar_small
jnanabhumiap.in 说:
2024年1月22日 16:32

JNANABHUMI AP provides all the latest educational updates and many more. The main concept or our aim behind this website has been the will to provide resources with full information on each topic jnanabhumiap.in which can be accessed through the Internet. To ensure that every reader gets what is important and worthy about the topic they search and link to hear from us.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter