/*\ * LBPP - A GNU Compiler Compiler (GCC) Liberty Basic Frontend * Copyright (C) 2001 Anthony Liguori * * LBPP is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * LBPP is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \*/ #include #include #include #include #include "lbpp.h" void translate_label(FILE *f, int i) { fprintf(f, "label_%d:\n", i); fprintf(f, "setjmp(cxt->labels[%d].jmp);\n", i); fprintf(f, "if (setting_labels)\n" "{\n" " goto label_%d;\n" "}\n", i + 1); } void translate_assignment(FILE *f, char *ptr) { char *asgn = ptr; char *name = ptr; char *end = skip_symbol(ptr); int i = 0; if (!strncasecmp(name, LET_STR, end - name) && (strlen(LET_STR) == end - name)) { name = skip_space(end); } i = lookup_variable(name); if (i == -1) { i = add_variable(name); } asgn = skip_symbol(name); asgn = skip_space(asgn); asgn = skip_param(asgn); asgn = skip_space(asgn); assert(*asgn == '='); asgn = skip_space(++asgn); if (var_table[i].type == DOUBLE) { translate_variable(f, name); fprintf(f, " = "); translate_expr(f, asgn); asgn = skip_expr(asgn); fprintf(f, ";\n"); } else if (var_table[i].type == STRING) { fprintf(f, "lbstr_set(&("); translate_variable(f, name); fprintf(f, "),"); translate_string(f, asgn); asgn = skip_string(asgn); fprintf(f, ");\n"); } else { fprintf(f, "Unknown lvalue type: %s\n", ptr); } asgn = skip_space(asgn); if (*asgn == ':') { translate_line(f, asgn + 1); } } int match_statement(char *buf, Statement *stmt) { char *ptr = buf; char *end = skip_symbol(ptr); int i; if (!strncasecmp(ptr, stmt->name, (end - ptr)) && (strlen(stmt->name) == (end - ptr))) { ptr = skip_space(end); for (i = 0; *ptr && i < stmt->arg_size; i++) { if (stmt->arg[i].literal) { end = ptr + strlen(stmt->arg[i].arg.string); if (strncasecmp(ptr, stmt->arg[i].arg.string, end - ptr) || strlen(stmt->arg[i].arg.string) != end - ptr) { break; } ptr = end; } else { if (stmt->arg[i].arg.type != VAR_ARG && stmt->arg[i].reference) { ptr = skip_symbol(ptr); ptr = skip_space(ptr); ptr = skip_param(ptr); } else { switch (stmt->arg[i].arg.type) { case STRING: ptr = skip_string(ptr); break; case DOUBLE: ptr = skip_expr(ptr); break; case HANDLE: if (*ptr == '#') { ptr = skip_symbol(++ptr); } break; case KEYWORD: ptr = skip_symbol(ptr); break; case LABEL: if (*ptr == '[') { ptr = strchr(ptr, ']') + 1; } break; case VAR_ARG: ptr = skip_vararg(ptr); break; default: break; } } } ptr = skip_space(ptr); } if (i == stmt->arg_size) { ptr = skip_space(ptr); if (!*ptr || *ptr == '\'' || *ptr == ':') { stmt->dirty = 1; return 1; } } } return 0; } void translate_vararg(FILE *f, char *buf) { char *ptr = buf; Type type = UNKNOWN; peek_expr(ptr, &type); if (type == STRING) { fprintf(f, "lb_va_adds("); translate_string(f, ptr); ptr = skip_string(ptr); } else if (type == DOUBLE) { fprintf(f, "lb_va_addd("); translate_expr(f, ptr); ptr = skip_expr(ptr); } else { fprintf(f, "lb_va_end(VA_END_SOFT)"); return; } ptr = skip_space(ptr); if (*ptr == ';') { fprintf(f, ", "); translate_vararg(f, skip_space(++ptr)); fprintf(f, ")"); } else { fprintf(f, ", lb_va_end(VA_END_HARD))"); } } void translate_vararg_ref(FILE *f, char *buf) { char *ptr = buf; int i = lookup_variable(buf); if (i == -1) { i = add_variable(buf); } fprintf(f, "lb_va_addv(&(cxt->vars[%d]), ", i); ptr = skip_symbol(ptr); ptr = skip_space(ptr); if (*ptr == ',') { translate_vararg_ref(f, skip_space(++ptr)); } else { fprintf(f, "lb_va_end(VA_END_SOFT)"); } fprintf(f, ")"); } void translate_statement(FILE *f, char *buf) { char *ptr = buf; int i; for (i = 0; i < statement_table_size; i++) { if (match_statement(ptr, &statement_table[i])) { break; } } if (i == statement_table_size) { char *end = skip_symbol(ptr); if (!strncasecmp(ptr, "IF", 2) && ((end - ptr) == 2)) { ptr = skip_space(ptr + 2); end = skip_bool(ptr); fprintf(f, "if ("); translate_bool(f, ptr); fprintf(f, ")\n{\n"); ptr = skip_space(end); end = skip_symbol(ptr); assert(!strncasecmp(ptr, "THEN", 4) && ((end - ptr) == 4)); ptr = skip_space(end); if (*ptr) { translate_line(f, ptr); fprintf(f, "}\n"); } } else if (!strncasecmp(ptr, "WHILE", 5) && ((end - ptr) == 5)) { ptr = skip_space(ptr + 5); end = skip_bool(ptr); fprintf(f, "while ("); translate_bool(f, ptr); fprintf(f, ")\n{\n"); ptr = skip_space(end); } else { fprintf(f, "#error %s\n", ptr); } } else { if (!strcasecmp(statement_table[i].name, "GOTO")) { char *label = skip_symbol(ptr); int j = 0; label = skip_space(label); j = lookup_label(label); if (j == -1) { j = add_label(label); } fprintf(f, "longjmp(cxt->labels[%d].jmp, 1);\n", j); ptr = skip_space(skip_symbol(label + 1) + 1); } else if (!strcasecmp(statement_table[i].name, "GOSUB")) { char *label = skip_symbol(ptr); int j = 0; label = skip_space(label); j = lookup_label(label); if (j == -1) { j = add_label(label); } fprintf(f, "if (setjmp(tmp_jmp) == 0) {\n"); fprintf(f, " lb_push_label(cxt, &tmp_jmp);\n"); fprintf(f, " longjmp(cxt->labels[%d].jmp, 1);\n}\n", j); ptr = skip_space(skip_symbol(label + 1) + 1); } else if (!strcasecmp(statement_table[i].name, "RETURN")) { fprintf(f, "lb_pop_label(cxt, &tmp_jmp);\n"); fprintf(f, "longjmp(tmp_jmp, 1);\n"); ptr = skip_space(skip_symbol(ptr)); } else if (!strcasecmp(statement_table[i].name, "FOR")) { char *lvalue; char *double1; char *double2; char *double3 = "1"; // This formula needs to be simplified! Big time... // FOR = TO [STEP ] // for (%1 = %2; // %1 != (double)((int)((%3 - %2) / %4)) * %4 + %4 + %2; // %1 += %4) lvalue = ptr = skip_space(skip_symbol(ptr)); ptr = skip_space(skip_param(skip_space(skip_symbol(ptr)))); ptr = skip_space(++ptr); double1 = ptr; ptr = skip_space(skip_expr(ptr)); ptr = skip_space(skip_symbol(ptr)); double2 = ptr; ptr = skip_space(skip_expr(ptr)); if (statement_table[i].arg_size == 7) { ptr = skip_space(skip_symbol(ptr)); double3 = ptr; } fprintf(f, "for ("); translate_variable(f, lvalue); fprintf(f, " = "); translate_expr(f, double1); fprintf(f, "; "); translate_variable(f, lvalue); fprintf(f, " != (double)((int)(("); translate_expr(f, double2); fprintf(f, " - "); translate_expr(f, double1); fprintf(f, ") / "); translate_expr(f, double3); fprintf(f, ")) * "); translate_expr(f, double3); fprintf(f, " + "); translate_expr(f, double3); fprintf(f, " + "); translate_expr(f, double1); fprintf(f, "; "); translate_variable(f, lvalue); fprintf(f, " += "); translate_expr(f, double3); fprintf(f, ")\n{\n"); } else if (!strcasecmp(statement_table[i].name, "NEXT")) { fprintf(f, "}\n"); ptr = skip_space(skip_symbol(skip_space(skip_symbol(ptr)))); } else if (!strcasecmp(statement_table[i].name, "WEND")) { fprintf(f, "}\n"); ptr = skip_space(skip_symbol(skip_space(skip_symbol(ptr)))); } else if (!strcasecmp(statement_table[i].name, "END") && (statement_table[i].arg_size == 1) && statement_table[i].arg[0].literal && !strcasecmp(statement_table[i].arg[0].arg.string, "IF")) { fprintf(f, "}\n"); ptr = skip_space(skip_symbol(skip_space(skip_symbol(ptr)))); } else { Statement *stmt = &statement_table[i]; fprintf(f, "LB_%s_%d(cxt", stmt->name, stmt->arg_size); ptr += strlen(stmt->name); ptr = skip_space(ptr); for (i = 0; i < stmt->arg_size; i++) { if (stmt->arg[i].literal) { ptr += strlen(stmt->arg[i].arg.string); } else { fprintf(f, ", "); if ((stmt->arg[i].arg.type != VAR_ARG) && stmt->arg[i].reference) { int i = lookup_variable(ptr); if (i == -1) { i = add_variable(ptr); } fprintf(f, "&(cxt->vars[%d])", i); ptr = skip_symbol(ptr); ptr = skip_space(ptr); ptr = skip_param(ptr); } else { switch(stmt->arg[i].arg.type) { case STRING: translate_string(f, ptr); ptr = skip_string(ptr); break; case DOUBLE: translate_expr(f, ptr); ptr = skip_expr(ptr); break; case HANDLE: translate_variable(f, ptr); ptr = skip_symbol(ptr); break; case KEYWORD: fprintf(f, "\""); fwrite(ptr, skip_symbol(ptr) - ptr, 1, f); fprintf(f, "\""); ptr = skip_symbol(ptr); break; case LABEL: { int i = lookup_label(ptr); if (i == -1) { i = add_label(ptr); } fprintf(f, "&(cxt->labels[%d])", i); ptr = skip_symbol(ptr + 1) + 1; break; } case VAR_ARG: if (stmt->arg[i].reference) { translate_vararg_ref(f, ptr); } else { translate_vararg(f, ptr); } ptr = skip_vararg(ptr); break; default: break; } } } ptr = skip_space(ptr); } fprintf(f, ");\n"); } if (*ptr == ':') { translate_line(f, skip_space(ptr + 1)); } } } void translate_string(FILE *f, char *buf) { char *ptr = buf; char *la = ptr; if (*ptr == '\"') { la = skip_string_lit(ptr); } else { la = skip_symbol(ptr); la = skip_space(la); la = skip_param(la); } la = skip_space(la); if (*la == '+') { fprintf(f, "lbstr_cat("); } if (*ptr == '\"') { char *end = skip_string_lit(ptr); fprintf(f, "lbstr_cstr("); fwrite(ptr, end - ptr, 1, f); fprintf(f, ")"); } else { fprintf(f, "lbstr_dup("); translate_variable(f, ptr); fprintf(f, ")"); } if (*la == '+') { fprintf(f, ","); translate_string(f, skip_space(++la)); fprintf(f, ")"); } } void translate_function(FILE *f, char *buf, int index) { char *ptr = buf; Function *func = &function_table[index]; int i; fprintf(f, "LB_%s_%d(cxt", func->name, func->arg_size); ptr += strlen(func->name); ptr = skip_space(ptr); assert(*ptr == '('); ptr++; for (i = 0; i < func->arg_size; i++) { fprintf(f, ", "); switch (func->arg[i].arg.type) { case DOUBLE: translate_expr(f, ptr); ptr = skip_expr(ptr); break; case STRING: translate_string(f, ptr); ptr = skip_string(ptr); break; case HANDLE: translate_variable(f, ptr); ptr = skip_symbol(ptr); break; default: break; } ptr = skip_space(ptr); if (*ptr != ',') { break; } else { ptr = skip_space(++ptr); } } fprintf(f, ")"); } void translate_variable(FILE *f, char *buf) { char *ptr = buf; int i = lookup_function(ptr); int func = 1; if (i == -1) { func = 0; i = lookup_variable(ptr); if (i == -1) { i = add_variable(ptr); } } if (func) { translate_function(f, ptr, i); } else { switch (var_table[i].type) { case STRING: fprintf(f, "cxt->vars[%d].data.str", i); break; case DOUBLE: fprintf(f, "cxt->vars[%d].data.db", i); break; case HANDLE: fprintf(f, "cxt->vars[%d].data.hnd", i); default: break; } if (var_table[i].rows > 1 || var_table[i].columns > 1) { ptr = skip_symbol(ptr); ptr = skip_space(ptr); assert(*ptr == '('); ptr = skip_space(++ptr); fprintf(f, "_v[(int)("); translate_expr(f, ptr); ptr = skip_expr(ptr); fprintf(f, " - 1 + "); if (var_table[i].columns > 1) { ptr = skip_space(ptr); assert(*ptr == ','); ptr = skip_space(++ptr); fprintf(f, "(("); translate_expr(f, ptr); ptr = skip_expr(ptr); fprintf(f, " - 1) * cxt->vars[%d].columns)", i); } else { fprintf(f, "0"); } fprintf(f, ")]"); ptr = skip_space(ptr); assert(*ptr == ')'); ptr++; } } } void translate_expr(FILE *f, char *buf) { char *ptr = buf; int done = 0; while (done == 0) { switch (*ptr) { case '(': fprintf(f, "("); translate_expr(f, ++ptr); if (*ptr == ')') { fprintf(f, ")"); ptr++; } break; default: if (isalpha(*ptr)) { int i = lookup_function(ptr); if (i != -1) { translate_function(f, ptr, i); } else { translate_variable(f, ptr); } ptr = skip_symbol(ptr); ptr = skip_space(ptr); ptr = skip_param(ptr); } else if(isdigit(*ptr) || (*ptr == '-' && isdigit(ptr[1]))) { char *end = skip_symbol(ptr); fwrite(ptr, end - ptr, 1, f); ptr = end; } else { done = 1; } break; } ptr = skip_space(ptr); switch (*ptr) { case '+': case '-': case '/': case '*': fprintf(f, " %c ", *ptr); ptr = skip_space(++ptr); break; case '\\': fprintf(f, "fixme: integer divide"); ptr = skip_space(++ptr); break; default: done = 1; break; } } } void translate_line(FILE *f, char *buf) { char *ptr = skip_space(buf); char *end = skip_symbol(ptr); int i; if (!*ptr || (*ptr == COMMENT_CHAR) || (!strncasecmp(ptr, COMMENT_STR, sizeof(COMMENT_STR) - 1))) { return; } if (*ptr == '[') { i = lookup_label(ptr); if (i == -1) { i = add_label(ptr); } translate_label(f, i); } else if(!strncasecmp(ptr, DIM_STR, end - ptr) && (strlen(DIM_STR) == (end - ptr))) { add_variable(skip_space(end)); } else if((!strncasecmp(ptr, LET_STR, end - ptr) && (strlen(LET_STR) == (end - ptr))) || check_assignment(ptr)) { translate_assignment(f, ptr); } else if (!strncasecmp(ptr, DECLARE_STR, end - ptr) && (strlen(DECLARE_STR) == end - ptr)) { ptr = skip_space(end); end = skip_symbol(ptr); if (!strncasecmp(ptr, STATEMENT_STR, end - ptr) && (strlen(STATEMENT_STR) == end - ptr)) { add_statement(skip_space(end)); } else if (!strncasecmp(ptr, FUNCTION_STR, end - ptr) && (strlen(FUNCTION_STR) == end - ptr)) { add_function_decl(skip_space(end)); } } else if (*ptr) { translate_statement(f, ptr); } } typedef enum _string_cmp { UNK, EQ, NEQ, GTEQ, LTEQ, GT, LT } StringCmp; char *translate_bool_t(FILE *f, char *buf, Type type) { char *ptr = buf; int more = 0; int right = 1; StringCmp comp = EQ; do { if (*ptr == '(') { ptr = translate_bool_t(f, skip_space(ptr + 1), type); assert(*ptr == ')'); ptr++; } else { if (type == UNKNOWN) { peek_expr(ptr, &type); } if (type == DOUBLE) { translate_expr(f, ptr); ptr = skip_expr(ptr); } else if (type == STRING) { if (right) { fprintf(f, "lbstr_cmp("); translate_string(f, ptr); } else { fprintf(f, ", "); translate_string(f, ptr); fprintf(f, ")"); switch(comp) { case EQ: fprintf(f, " == 0"); break; case NEQ: fprintf(f, " != 0"); break; case GTEQ: fprintf(f, " != -1"); break; case LTEQ: fprintf(f, " != 1"); break; case GT: fprintf(f, " == 1"); break; case LT: fprintf(f, " == -1"); break; default: break; } } ptr = skip_string(ptr); } } comp = UNK; more = 1; switch (*ptr) { case '>': comp = GT; if (*(++ptr) == '=') { comp = GTEQ; ptr++; } break; case '<': comp = LT; if ((*(++ptr) == '=') || (*ptr == '>')) { if (*ptr == '=') { comp = LTEQ; } else { comp = NEQ; } ptr++; } break; case '=': comp = EQ; ptr++; break; default: { char *end = skip_symbol(ptr); if (!strncasecmp(ptr, "and", 3) && ((end - ptr) == 3)) { ptr += 3; type = UNKNOWN; fprintf(f, " && "); } else if (!strncasecmp(ptr, "or", 2) && ((end - ptr) == 2)) { ptr += 2; type = UNKNOWN; fprintf(f, " || "); } else { more = 0; } } break; } if (right && type == DOUBLE) { switch(comp) { case EQ: fprintf(f, " == "); break; case NEQ: fprintf(f, " != "); break; case GTEQ: fprintf(f, " >= "); break; case LTEQ: fprintf(f, " <= "); break; case GT: fprintf(f, " > "); break; case LT: fprintf(f, " < "); break; default: break; } } right = (!right); ptr = skip_space(ptr); } while (more); return ptr; } void translate_bool(FILE *f, char *ptr) { translate_bool_t(f, ptr, UNKNOWN); }