⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 basic.c

📁 简单basic语言编译器
💻 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);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -