#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "db.h" #include "externs.h" #include "softcode.h" static void add_if(PROG *program, int test) { SCIF *newif; PROGLINE *p, *pelse = NULL; int deep = 0; char *command; if(test == -1) { syntax_error(); return; } newif = (SCIF *)stack_alloc(sizeof(SCIF), 1, 0); newif->test = test; for(p = code_ptr->pline->next;p;p = p->next) { command = get_command(p->code); if(!string_compare(command, "for")) deep++; else if(!string_compare(command, "next")) deep--; if(!string_compare(command, "if")) deep++; else if(!string_compare(command, "endif")) { if(!deep--) break; } else if(!string_compare(command, "else")) if(!deep) { if(pelse) { notify(code_ptr->executor, tprintf("|+R|Too many ELSE statements in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); notify(code_ptr->executor, tprintf("|+R|First ELSE in |+Y|%d|+R|.", pelse->line)); notify(code_ptr->executor, tprintf("%d %s", pelse->line, pelse->code)); end_program(code_ptr->program, 0); return; } else pelse = p; } } if(!p) { notify(code_ptr->executor, tprintf("|+R|IF with no ENDIF in %d", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } newif->endif = p; if(!test) { if(pelse) code_ptr->pline = pelse; else code_ptr->pline = p; } newif->next = code_ptr->iflist; code_ptr->iflist = newif; } static int test_if(char *ifstr) { char buf[4096]; char left[4096], op[4096], right[4096]; char *p = NULL; int leftmath, rightmath; int i, val; char *operators[] = { ">", "<", ">=", "<=", "!=", "=" }; for(i = 0;i < 6;++i) if((p = strstr(ifstr, operators[i]))) break; if(p) { strncpy(buf, ifstr, p-ifstr); *(buf+(p-ifstr)) = '\0'; if((leftmath = parse_output(buf, left)) == -1) return(-1); strncpy(op, p, strlen(operators[i])); *(op+strlen(operators[i])) = '\0'; if((rightmath = parse_output(p+strlen(operators[i]), right)) == -1) return(-1); if(!*right) return(-1); } else { if((leftmath = parse_output(ifstr, left)) == -1) return(-1); if(leftmath) return(atoi(left)); return(*left); } if((leftmath && !rightmath) || (!leftmath && rightmath)) { notify(code_ptr->executor, tprintf("|+R|Type Mismatch in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return(-1); } if(!leftmath) { val = strcmp(left, right); if(!strcmp(op, "<")) return((val < 0)); if(!strcmp(op, ">")) return((val > 0)); if(!strcmp(op, "=")) return(!val); if(!strcmp(op, ">=")) return((val >= 0)); if(!strcmp(op, "<=")) return((val <= 0)); return(val); /* != */ } if(!strcmp(op, "<")) return((atoi(left) < atoi(right))); if(!strcmp(op, ">")) return((atoi(left) > atoi(right))); if(!strcmp(op, "=")) return((atoi(left) == atoi(right))); if(!strcmp(op, "<=")) return((atoi(left) <= atoi(right))); if(!strcmp(op, ">=")) return((atoi(left) >= atoi(right))); return((atoi(left) != atoi(right))); /* != */ } void sc_do_if(char *arg1, char *arg2) { char ifstr[4096]; if(*arg2) sprintf(ifstr, "%s=%s", arg1, arg2); else strcpy(ifstr, arg1); add_if(code_ptr->program, test_if(ifstr)); } void sc_do_else() { if(!code_ptr->iflist) { notify(code_ptr->executor, tprintf("|+R|ELSE statement not within IF in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } if(code_ptr->iflist->test) code_ptr->pline = code_ptr->iflist->endif; else return; } void sc_do_endif() { SCIF *freeme; if(!code_ptr->iflist) { notify(code_ptr->executor, tprintf("|+R|ENDIF statement not within IF in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } freeme = code_ptr->iflist; code_ptr->iflist = code_ptr->iflist->next; stack_free(freeme); } static void add_for(int max, int step, PROGLINE *pnext, SCVAR *var) { SCFOR *newfor; newfor = (SCFOR *)stack_alloc(sizeof(SCFOR), 1, 0); newfor->top = code_ptr->pline; newfor->max = max; newfor->step = step; newfor->pnext = pnext; newfor->var = var; newfor->next = code_ptr->forlist; code_ptr->forlist = newfor; } void sc_do_for(char *arg1, char *arg2) { PROGLINE *pline; char *p, *b; char buf[4096], buf2[4096]; int max; int step; int deep; SCVAR *var; if(*arg1 != '~' || *last_char(arg1) == '$') { syntax_error(); return; } ivar_val(arg1+1); /* This will create the var if it doesn't exist */ if(!code_ptr) /* Illegal var name */ return; var = find_var(arg1+1, VAR_NUM); for(p = arg2, b = buf;*p && !isspace(*p);++p, ++b) *b = *p; *b = '\0'; if(!*p || parse_output(buf, buf2) != 1) { syntax_error(); return; } var->nvalue = atoi(buf2); p++; strcpy(buf, "TO"); for(b = buf;*b;++p, ++b) { if(toupper(*p) != *b) { syntax_error(); return; } } if(!isspace(*p++)) { syntax_error(); return; } for(b = buf;*p && !isspace(*p);p++, b++) *b = *p; *b = '\0'; if(parse_output(buf, buf2) != 1) { syntax_error(); return; } max = atoi(buf2); while(*p && !isspace(*p)) p++; if(!*p) step = 1; else { p++; strcpy(buf, "STEP"); for(b = buf;*b;p++, b++) { if(toupper(*p) != *b) { syntax_error(); return; } } if(!isspace(*p++)) { syntax_error(); return; } if(parse_output(p, buf) != 1) { syntax_error(); return; } step = atoi(buf); } deep = 0; for(pline = code_ptr->pline->next;pline;pline = pline->next) { if((p = strchr(pline->code, ' '))) { strncpy(buf, pline->code, p-pline->code); *(buf+(p-pline->code)) = '\0'; } else strcpy(buf, pline->code); if(!string_compare(buf, "if")) deep++; else if(!string_compare(buf, "endif")) deep--; else if(!string_compare(buf, "for")) deep++; else if(!string_compare(buf, "next")) if(!deep--) break; } if(!pline) { notify(code_ptr->executor, tprintf("|+R|FOR without NEXT in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } add_for(max, step, pline, var); } void sc_do_next() { SCFOR *freeme; if(!code_ptr->forlist) { notify(code_ptr->executor, tprintf("|+R|NEXT without FOR in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } code_ptr->forlist->var->nvalue += code_ptr->forlist->step; if(code_ptr->forlist->var->nvalue > code_ptr->forlist->max) { code_ptr->pline = code_ptr->forlist->pnext; freeme = code_ptr->forlist; code_ptr->forlist = code_ptr->forlist->next; stack_free(freeme); return; } code_ptr->pline = code_ptr->forlist->top; } void sc_do_wait(char *arg) { int sec; if(!*arg) { syntax_error(); return; } sec = atoi(arg); if(sec < 1 || sec > 65535) { syntax_error(); return; } code_ptr->wait = now+sec; } void sc_do_end() { end_program(code_ptr->program, 1); } void sc_do_goto(char *arg) { PROGLINE *pline; int linenum; linenum = atoi(arg); for(pline = code_ptr->program->program;pline;pline = pline->next) if(pline->line == linenum) break; if(!pline) { notify(code_ptr->executor, tprintf("|+R|Invalid line reference in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } code_ptr->pline = pline; code_ptr->advance = 0; } void sc_do_gosub(char *arg) { SCGOSUB *newgosub; PROGLINE *pline, *pline2; int linenum; int deep = 0; char *command; linenum = atoi(arg); for(pline = code_ptr->program->program;pline;pline = pline->next) if(pline->line == linenum) break; if(!pline) { notify(code_ptr->executor, tprintf("|+R|Invalid line reference in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } for(pline2 = code_ptr->pline->next;pline2;pline2 = pline2->next) { command = get_command(pline2->code); if(!string_compare(command, "gosub")) deep++; else if(!string_compare(command, "return")) if(!deep--) break; } if(!pline2) { notify(code_ptr->executor, tprintf("|+R|GOSUB without RETURN in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } newgosub = (SCGOSUB *)stack_alloc(sizeof(SCGOSUB), 1, 0); newgosub->top = code_ptr->pline; newgosub->next = code_ptr->gosublist; code_ptr->gosublist = newgosub; code_ptr->pline = pline; code_ptr->advance = 0; } void sc_do_return() { SCGOSUB *freeme; if(!code_ptr->gosublist) { notify(code_ptr->executor, tprintf("|+R|RETURN not within GOSUB in |+Y|%d|+R|.", code_ptr->pline->line)); notify(code_ptr->executor, tprintf("%d %s", code_ptr->pline->line, code_ptr->pline->code)); end_program(code_ptr->program, 0); return; } code_ptr->pline = code_ptr->gosublist->top; freeme = code_ptr->gosublist; code_ptr->gosublist = code_ptr->gosublist->next; stack_free(freeme); }