summaryrefslogtreecommitdiff
path: root/src/user/app/kbasic/control.c
diff options
context:
space:
mode:
authorAlex AUVOLAT <alexis211@gmail.com>2013-06-08 23:09:52 +0200
committerAlex AUVOLAT <alexis211@gmail.com>2013-06-08 23:09:52 +0200
commit4d65fcb9a8b6c7c6fd5a3390c46a96d11b6a80d4 (patch)
treec193acf64ff2db985f6664f161cf586c3caeb684 /src/user/app/kbasic/control.c
parenteae9997d3c2dbaef53022ddabe61c1800a619499 (diff)
downloadTCE-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.c511
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);
+ }
+}