📄 bas-int.c
字号:
/* A tiny BASIC interpreter */
#include "stdio.h"
#include "setjmp.h"
#include "math.h"
#include "ctype.h"
#include "stdlib.h"
#include "string.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[] = { /* Commands 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,
"", END /* mark end of table */
};
char token[80];
char token_type, tok;
struct label {
char name[LAB_LEN];
char *p; /* points to place to go in source file*/
};
struct label label_table[NUM_LAB];
char *find_label(), *gpop();
int load_program();
int get_next_label();
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 stack */
void print(), scan_labels(), find_eol(), exec_goto();
void exec_if(), exec_for(), next(), fpush(), input();
void gosub(), greturn(), gpush(), label_init();
void serror(), get_exp(), putback();
void level2(), level3(), level4(), level5(), level6(), primitive();
void unary(), arith();
int iswhite();
int isdelim();
int look_up();
int find_var();
int assignment();
int get_token();
main(argc, argv)
int argc;
char *argv[];
{
char *p_buf;
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 buffer */
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 statement */
if(token_type==VARIABLE) {
putback(); /* return the var to the input stream */
assignment(); /* must be assignment statement */
}
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);
}
/* Load a program. */
int load_program(p, fname)
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;
/* get the variable name */
get_token();
if(!isalpha(*token)) {
serror(4);
return 0;
}
var = toupper(*token)-'A';
/* get the equals sign */
get_token();
if(*token!='=') {
serror(3);
return 0;
}
/* get the value to assign to var */
get_exp(&value);
/* assign the value */
variables[var] = value;
return 1;
}
/* 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(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 spaces to move to next tab */
spaces = 8 - (len % 8);
len += spaces; /* add in the tabbing position */
while(spaces) {
printf(" ");
spaces--;
}
}
else if(*token==',') /* do nothing */;
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 pointer to top of program */
/* if the first token in the file is a label */
get_token();
if(token_type==NUMBER) {
}
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 the next line. */
void find_eol()
{
while(*prog!='\n' && *prog!='\0') ++prog;
if(*prog) prog++;
}
/* Return index of next free position in label array.
A -1 is returned if the array is full.
A -2 is returned when duplicate label is found.
*/
get_next_label(s)
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; otherwise a pointer to the position
of the label is returned.
*/
char *find_label(s)
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 the label */
loc = find_label(token);
if(loc=='\0')
serror(7); /* label not defined */
else prog=loc; /* start program running at that loc */
}
/* Initialize the array that holds the labels.
By convention, a null label name indicates that
array position 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 expression */
get_token(); /* get the operator */
if(!strchr("=<>", *token)) {
serror(0); /* not a legal operator */
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 equals sign */
if(*token!='=') {
serror(3);
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -