diff options
author | Alex AUVOLAT <alexis211@gmail.com> | 2013-06-08 23:09:52 +0200 |
---|---|---|
committer | Alex AUVOLAT <alexis211@gmail.com> | 2013-06-08 23:09:52 +0200 |
commit | 4d65fcb9a8b6c7c6fd5a3390c46a96d11b6a80d4 (patch) | |
tree | c193acf64ff2db985f6664f161cf586c3caeb684 /src/user/app/kbasic/control.c | |
parent | eae9997d3c2dbaef53022ddabe61c1800a619499 (diff) | |
download | TCE-4d65fcb9a8b6c7c6fd5a3390c46a96d11b6a80d4.tar.gz TCE-4d65fcb9a8b6c7c6fd5a3390c46a96d11b6a80d4.zip |
All FWIK is deleted. YOSH is now pure C. Not-working KBASIC included.
Diffstat (limited to 'src/user/app/kbasic/control.c')
-rw-r--r-- | src/user/app/kbasic/control.c | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/src/user/app/kbasic/control.c b/src/user/app/kbasic/control.c new file mode 100644 index 0000000..1ab22ff --- /dev/null +++ b/src/user/app/kbasic/control.c @@ -0,0 +1,511 @@ +#include <stdio.h> +#include <string.h> +// #include <sys/wait.h> +// #include <unistd.h> +#include <ctype.h> +#include <stdlib.h> +#include <setjmp.h> + +#include "basic.h" + +struct label { + char name[LAB_LEN]; + char *p; /* points to place to go in source file*/ +}; +struct for_stack { + int *var; /* counter variable */ + int target; /* target value */ + char *loc; +}; + +struct label label_table[NUM_LAB]; + +char *gstack[SUB_NEST]; /* stack for gosub */ +struct for_stack fstack[FOR_NEST]; /* stack for FOR/NEXT loop */ + +int ftos; /* index to top of FOR stack */ +int gtos; /* index to top of GOSUB stack */ + +char *program, *prog_ip; /* holds expression to be analyzed */ + +char *interp_name; + +jmp_buf e_buf; /* hold environment for longjmp() */ + +char *find_label(); +void scan_labels(); +struct for_stack fpop(); +char *gpop(); +int get_next_label(char *); +void fpush(struct for_stack); +void gosub(), greturn(), gpush(char*), label_init(); +void exec_if(), exec_for(), next(), exec_goto(); +void exec_exec(), exec_load(); +void exec_list(); + +/* initialize variables */ +void init() { + program = NULL; + prog_ip = NULL; + label_init(); +} + +/* Load program and scans labels */ +void load_program (char *p_buf) { + if (program != NULL) { + free(program); + } + + program = p_buf; + scan_labels(); /* find the labels in the program */ +} + +/* Insert line at the right place of program */ +void insert_line(char *l, int n) { + char *a, *b, *p; + int i_n, t, k; + + + if (program == NULL) { + load_program(strdup(l)); + } else { + int prog_l = strlen(program); + + // lookup insert position + // find smallest label above line number + a = (n == 0 ? program : program + prog_l); + i_n = -1; b = program + prog_l; + + for (t = 0; t < NUM_LAB; t++) { + if (label_table[t].name[0]) { + k = atoi(label_table[t].name); + if (k == n) { + a = label_table[t].p; + while (*a != '\n' && a > program) a--; // back to beginning of line + if (*a == '\n') a++; + } + if (k > n && (k < i_n || i_n == -1)) { + i_n = k; + b = label_table[t].p; + while (*b != '\n' && b > program) b--; // back to beginning of line + if (*b == '\n') b++; + if (b < a) a = b; + } + } + } + + p = malloc(prog_l + strlen(l) + 3); + + strncpy(p, program, (a - program)); // copy [0, a[ + p[a - program] = 0; + // if l is an empty line, do not copy. + for (i_n = 0; l[i_n]; i_n++) { + if (!isdigit(l[i_n]) && l[i_n] != '\n' && l[i_n] != '\r') { + strcpy(p + (a - program), l); // copy l + break; + } + } + strcat(p + (a - program), b); // copy [b, end[ + + load_program(p); // reparse labels + } +} + +/* start program execution at given entry point (not necessarily in loaded program) + return values : + - 0 : return on end of input + - 1 : return on error + - 2 : return on "END" statement + - 3 : return on "LOAD" statement +*/ +int start(char *entry) { + ftos = 0; /* initialize the FOR stack index */ + gtos = 0; /* initialize the GOSUB stack index */ + + prog_ip = entry; + if(setjmp(e_buf)) return 1; /* initialize the long jump buffer */ + + 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 LIST: + exec_list(); + break; + case PRINT: + exec_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 EXEC: + exec_exec(); + break; + case LOAD: + exec_load(); + return 3; + case RUN: // (re)start program at begining + ftos = gtos = 0; + prog_ip = program; + break; + case END: // end program execution + return 2; + } + } while (prog_ip != NULL && tok != FINISHED); + + return 0; +} + +/* display an error message */ +void serror(int error) +{ + static char *e[]= { + "syntax error", + "unbalanced parentheses", + "no expression present", + "equals sign expected", + "not a variable", + "Label table full", + "duplicate label", + "undefined label", + "THEN expected", + "TO expected", + "too many nested FOR loops", + "NEXT without FOR", + "too many nested GOSUBs", + "RETURN without GOSUB" + }; + printf ("[near '%s' %d %d] E: %s\n", token, tok, token_type, e[error]); + + longjmp(e_buf, 1); /* return to save point */ + exit(0); + +} + +/* Find all labels. */ +void scan_labels() +{ + int addr; + + label_init(); /* zero all labels */ + + if (program == 0) return; /* if no program is loaded, nothing to do. */ + + prog_ip = program; /* prog_ip will go through the program */ + + /* if the first token in the file is a label */ + get_token(); + if(token_type==NUMBER) { + strcpy(label_table[0].name,token); + label_table[0].p=prog_ip; + } + + 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); + } + strncpy(label_table[addr].name, token, LAB_LEN); + label_table[addr].name[LAB_LEN-1] = 0; // null terminate + label_table[addr].p = prog_ip; /* current point in program */ + } + /* if not on a blank line, find next line */ + if(tok!=EOL) find_eol(); + } while(tok!=FINISHED); +} + +/* 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. + */ +int 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; otherwise 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 the label */ + loc = find_label(token); + if(loc=='\0') + serror(7); /* label not defined */ + + else prog_ip=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=find_var(token); /* save its index */ + + get_token(); /* read the equals sign */ + if(*token!='=') { + serror(3); + return; + } + + get_exp(&value); /* get initial value */ + + *(i.var) = value; + + get_token(); + if(tok!=TO) serror(9); /* read and discard the TO */ + + get_exp(&i.target); /* get target value */ + + /* if loop can execute at least once, push info on stack */ + if(value>=*(i.var)) { + i.loc = prog_ip; + 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 */ + + (*(i.var))++; + if(*(i.var)>i.target) return; /* all done */ + fpush(i); /* otherwise, restore the info */ + prog_ip = 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]); +} + +/* 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_ip); /* save place to return to */ + prog_ip = loc; /* start program running at that loc */ + } +} + +/* Return from GOSUB. */ +void greturn() +{ + prog_ip = 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--]); +} + + +/* EXEC function + Forks and runs another instance of the interpreter + */ +void exec_exec() { + + /* TODO + int pid; + + get_token(); + if (token_type==QUOTE) { + pid = fork(); + if (pid < 0) { + printf("Error: could not fork.\n"); + } else { + if (pid == 0) { + execlp(interp_name, interp_name, token, 0); + printf("Error: could not exec.\n"); + exit(0); + } else { + wait(0); + } + } + get_token(); + } else { + serror(0); + } + */ + printf("EXEC not available.\n"); +} + +/* LOAD function + loads a program into interpreter and ends anything currently executing */ +void exec_load() { + char *p_buf; + + get_token(); + if (token_type==QUOTE) { + if (!(p_buf = load_file(token))) { + printf("Error: could not load file %s\n", token); + } else { + load_program(p_buf); + } + } else { + serror(0); + } +} + +/* LIST function + dumps program source text */ +void exec_list() { + get_token(); + + if (program == NULL) { + printf("No program loaded.\n"); + } else { + printf("%s", program); + } +} |