# HG changeset patch
# User lost@l-w.ca
# Date 1324602218 25200
# Node ID cca933d32298666507cbdef3c1385bda56986b3a
# Parent 6433cb02417468576dfc89508b0c881aabdef723
Clean up some mess in lwbasic directory
diff -r 6433cb024174 -r cca933d32298 lwbasic/attic/emit.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwbasic/attic/emit.c Thu Dec 22 18:03:38 2011 -0700
@@ -0,0 +1,51 @@
+/*
+emit.c
+
+Copyright © 2011 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 of the License, or (at your option) any later
+version.
+
+This program 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, see .
+*/
+
+/*
+This is the actual compiler bit; it drives the parser and code generation
+*/
+
+#include
+
+#define __emit_c_seen__
+#include "lwbasic.h"
+
+void emit_prolog(cstate *state, int vis)
+{
+ if (vis)
+ {
+ printf("\texport _%s\n", state -> currentsub);
+ }
+ printf("_%s\n", state -> currentsub);
+ if (state -> framesize > 0)
+ {
+ printf("\tleas %d,s\n", -(state -> framesize));
+ }
+}
+
+void emit_epilog(cstate *state)
+{
+ if (state -> framesize > 0)
+ {
+ printf("\tleas %d,s\n", state -> framesize);
+ }
+ printf("\trts\n");
+}
diff -r 6433cb024174 -r cca933d32298 lwbasic/attic/input.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwbasic/attic/input.c Thu Dec 22 18:03:38 2011 -0700
@@ -0,0 +1,85 @@
+/*
+input.c
+
+Copyright © 2011 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 of the License, or (at your option) any later
+version.
+
+This program 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, see .
+*/
+
+/*
+handle reading input for the rest of the system
+*/
+
+#include
+#include
+#include
+
+#include
+#include
+
+#define __input_c_seen__
+#include "lwbasic.h"
+
+struct input_state
+{
+ FILE *fp;
+ int error;
+};
+
+static void input_init(cstate *state)
+{
+ struct input_state *sp;
+
+ sp = lw_alloc(sizeof(struct input_state));
+ sp -> error = 0;
+
+ if (!(state -> input_file) || strcmp(state -> input_file, "-"))
+ {
+ sp -> fp = stdin;
+ }
+ else
+ {
+ sp -> fp = fopen(state -> input_file, "rb");
+ if (!(sp -> fp))
+ {
+ lwb_error("Cannot open input file\n");
+ }
+ }
+
+ state -> input_state = sp;
+}
+
+int input_getchar(cstate *state)
+{
+ int r;
+ struct input_state *sp;
+
+ if (!(state -> input_state))
+ input_init(state);
+ sp = state -> input_state;
+
+
+ if (sp -> error)
+ return -2;
+
+ if (feof(sp -> fp))
+ return -1;
+
+ r = fgetc(sp -> fp);
+ if (r == EOF)
+ return -1;
+ return r;
+}
diff -r 6433cb024174 -r cca933d32298 lwbasic/attic/lexer.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwbasic/attic/lexer.c Thu Dec 22 18:03:38 2011 -0700
@@ -0,0 +1,440 @@
+/*
+lexer.c
+
+Copyright © 2011 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 of the License, or (at your option) any later
+version.
+
+This program 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, see .
+*/
+
+/*
+This handles the gritty details of parsing tokens
+*/
+
+#include
+#include
+#include
+
+#include
+#include
+
+#define __lexer_c_seen__
+#include "lwbasic.h"
+
+/*
+A token idenfier is returned by lexer(). The actual string value
+is found in state->lexer_lexer_token_string; if the token as an integer value,
+it will be found in state->lexer_token_number in the appropriate "value"
+slot.
+*/
+
+struct token_list
+{
+ char *string;
+ int token;
+};
+
+/* keywords that appear as part of normal expressions */
+static struct token_list lexer_global_tokens[] =
+{
+ { "function", token_kw_function },
+ { "sub", token_kw_sub },
+ { "public", token_kw_public },
+ { "private", token_kw_private },
+ { "as", token_kw_as },
+ { "params", token_kw_params },
+ { "returns", token_kw_returns },
+ { "integer", token_kw_integer },
+ { "endsub", token_kw_endsub },
+ { "endfunction", token_kw_endfunction },
+ { "dim", token_kw_dim },
+ { NULL }
+};
+
+/* contains "built in" function names */
+static struct token_list lexer_expr_tokens[] =
+{
+ { "and", token_op_and },
+ { "or", token_op_or },
+ { "band", token_op_band },
+ { "bor", token_op_bor },
+ { "bxor", token_op_bxor },
+ { "xor", token_op_xor },
+ { "not", token_op_not },
+ { "bnot", token_op_bnot },
+ { NULL }
+};
+
+static char *lexer_token_names[] =
+{
+ "SUB",
+ "FUNCTION",
+ "AS",
+ "PUBLIC",
+ "PRIVATE",
+ "PARAMS",
+ "RETURNS",
+ "INTEGER",
+ "ENDSUB",
+ "ENDFUNCTION",
+ "DIM",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+};
+
+char *lexer_token_name(int token)
+{
+ if (token > token_eol)
+ return "???";
+ return lexer_token_names[token];
+}
+
+static int lexer_getchar(cstate *state)
+{
+ int c;
+ c = input_getchar(state);
+ if (c == -2)
+ {
+ lwb_error("Error reading input stream.");
+ }
+ return c;
+}
+
+static void lexer_nextchar(cstate *state)
+{
+ state -> lexer_curchar = lexer_getchar(state);
+ if (state -> lexer_curchar == state -> lexer_ignorechar)
+ state -> lexer_curchar = lexer_getchar(state);
+ state -> lexer_ignorechar = 0;
+}
+
+static int lexer_curchar(cstate *state)
+{
+ if (state -> lexer_curchar == -1)
+ {
+ lexer_nextchar(state);
+ }
+
+ return state -> lexer_curchar;
+}
+
+static void lexer_skip_white(cstate *state)
+{
+ int c;
+
+ for (;;)
+ {
+ c = lexer_curchar(state);
+ if (!(c == 0 || c == ' ' || c == '\t'))
+ return;
+ lexer_nextchar(state);
+ }
+}
+
+/* must not be called unless the word will be non-zero length */
+static void lexer_word(cstate *state)
+{
+ int wordlen = 0;
+ int wordpos = 0;
+ char *word = NULL;
+ int c;
+ struct token_list *tok = NULL;
+
+ for (;;) {
+ c = lexer_curchar(state);
+ if (c == '_' || (c >= '0' && c <= '9' ) || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c >= 0x80)
+ {
+ /* character is part of word */
+ if (wordpos >= wordlen)
+ {
+ word = lw_realloc(word, wordlen + 32);
+ wordlen += 32;
+ }
+ word[wordpos++] = c;
+ }
+ else
+ break;
+
+ lexer_nextchar(state);
+ }
+
+ word[wordpos] = 0;
+ lw_free(state -> lexer_token_string);
+ state -> lexer_token_string = lw_strdup(word);
+
+ switch (state -> parser_state)
+ {
+ default:
+ tok = lexer_global_tokens;
+ }
+
+ if (state -> expression)
+ {
+ tok = lexer_expr_tokens;
+ }
+
+ /* check for tokens if appropriate */
+ /* force uppercase */
+ if (tok)
+ {
+ for (c = 0; word[c]; c++)
+ if (word[c] >= 'A' && word[c] <= 'Z')
+ word[c] = word[c] + 0x20;
+
+ while (tok -> string)
+ {
+ if (strcmp(tok -> string, word) == 0)
+ break;
+ tok++;
+ }
+ }
+
+ lw_free(word);
+ if (tok && tok -> string)
+ state -> lexer_token = tok -> token;
+ else
+ state -> lexer_token = token_identifier;
+}
+
+static void lexer_parse_number(cstate *state, int neg)
+{
+ unsigned long tint = 0;
+ int c;
+
+ for (;;)
+ {
+ c = lexer_curchar(state);
+ if (c >= '0' && c <= '9')
+ {
+ tint *= 10 + (c - '0');
+ }
+ else
+ {
+ /* end of the number here */
+ if (neg)
+ {
+ if (tint > 0x80000000)
+ lwb_error("Integer overflow\n");
+ state -> lexer_token_number.integer = -tint;
+ state -> lexer_token = token_int;
+ }
+ else
+ {
+ state -> lexer_token = token_uint;
+ state -> lexer_token_number.uinteger = tint;
+ }
+ return;
+ }
+ lexer_nextchar(state);
+ }
+}
+
+static void lexer_empty_token(cstate *state)
+{
+ lw_free(state -> lexer_token_string);
+ state -> lexer_token_string = NULL;
+}
+
+void lexer(cstate *state)
+{
+ int c;
+
+ lexer_skip_white(state);
+
+ lexer_empty_token(state);
+
+ c = lexer_curchar(state);
+ if (c == -1)
+ {
+ state -> lexer_token = token_eof;
+ return;
+ }
+
+ if (c == '\n')
+ {
+ /* LF */
+ lexer_nextchar(state);
+ state -> lexer_ignorechar = '\r';
+ state -> lexer_token = token_eol;
+ return;
+ }
+
+ if (c == '\r')
+ {
+ /* CR */
+ lexer_nextchar(state);
+ state -> lexer_ignorechar = '\n';
+ state -> lexer_token = token_eol;
+ return;
+ }
+
+ if (c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c >= 0x80)
+ {
+ /* we have a word here; identifier, keyword, etc. */
+ lexer_word(state);
+ return;
+ }
+
+ if (state -> expression && c >= '0' && c <= '9')
+ {
+ /* we have a number */
+ lexer_parse_number(state, 0);
+ return;
+ }
+
+ lexer_nextchar(state);
+ if (state -> expression)
+ {
+ if (c == '-' && lexer_curchar(state) >= '0' && lexer_curchar(state) <= '9')
+ {
+ /* we have a negative number here */
+ lexer_parse_number(state, 1);
+ return;
+ }
+ if (c == '=')
+ {
+ state -> lexer_token = token_op_equality;
+ return;
+ }
+ if (c == '<')
+ {
+ if (lexer_curchar(state) == '=')
+ {
+ lexer_nextchar(state);
+ state -> lexer_token = token_op_lessequal;
+ return;
+ }
+ if (lexer_curchar(state) == '>')
+ {
+ lexer_nextchar(state);
+ state -> lexer_token = token_op_notequal;
+ return;
+ }
+ state -> lexer_token = token_op_less;
+ return;
+ }
+ if (c == '>')
+ {
+ if (lexer_curchar(state) == '>')
+ {
+ lexer_nextchar(state);
+ state -> lexer_token = token_op_greaterequal;
+ return;
+ }
+ if (lexer_curchar(state) == '<')
+ {
+ state -> lexer_token = token_op_notequal;
+ lexer_nextchar(state);
+ return;
+ }
+ state -> lexer_token = token_op_greater;
+ return;
+ }
+ switch(c)
+ {
+ case '+':
+ state -> lexer_token = token_op_plus;
+ return;
+
+ case '-':
+ state -> lexer_token = token_op_minus;
+ return;
+
+ case '/':
+ state -> lexer_token = token_op_divide;
+ return;
+
+ case '*':
+ state -> lexer_token = token_op_times;
+ return;
+
+ case '%':
+ state -> lexer_token = token_op_modulus;
+ return;
+
+ case '(':
+ state -> lexer_token = token_op_oparen;
+ return;
+
+ case ')':
+ state -> lexer_token = token_op_cparen;
+ return;
+
+ }
+ }
+ else
+ {
+ if (c == '=')
+ {
+ state -> lexer_token = token_op_assignment;
+ return;
+ }
+ }
+
+ /* return the character if all else fails */
+ state -> lexer_token = token_char;
+ state -> lexer_token_string = lw_realloc(state -> lexer_token_string, 2);
+ state -> lexer_token_string[0] = c;
+ state -> lexer_token_string[1] = 0;
+ return;
+}
+
+char *lexer_return_token(cstate *state)
+{
+ static char *buffer = NULL;
+ static int buflen = 0;
+ int l;
+
+ if (buflen == 0)
+ {
+ buffer = lw_alloc(128);
+ buflen = 128;
+ }
+
+ l = snprintf(buffer, buflen, "%s (%s)", state -> lexer_token_string, lexer_token_name(state -> lexer_token));
+ if (l >= buflen)
+ {
+ buffer = lw_realloc(buffer, l + 1);
+ buflen = l + 1;
+ snprintf(buffer, buflen, "%s (%s)", state -> lexer_token_string, lexer_token_name(state -> lexer_token));
+ }
+ return buffer;
+}
diff -r 6433cb024174 -r cca933d32298 lwbasic/attic/lwbasic.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwbasic/attic/lwbasic.h Thu Dec 22 18:03:38 2011 -0700
@@ -0,0 +1,148 @@
+/*
+lwbasic.h
+
+Copyright © 2011 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 of the License, or (at your option) any later
+version.
+
+This program 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, see .
+*/
+
+/*
+definitions used throughout lwbasic
+*/
+
+#ifndef __lwbasic_h_seen__
+#define __lwbasic_h_seen__
+
+#include
+
+#include "symtab.h"
+
+/* note: integer and uinteger will be the same for positive values from 0
+through 0x7FFFFFFF; the unsigned type should be used for doing ascii
+conversions and then if a negative value was discovered, it should be
+negated IFF it is in range. */
+
+union lexer_numbers
+{
+ uint32_t uinteger;
+ int32_t integer;
+};
+
+typedef struct
+{
+ char *output_file;
+ char *input_file;
+
+ int debug_level;
+
+ char *lexer_token_string;
+ union lexer_numbers lexer_token_number;
+ int lexer_token;
+ int lexer_curchar;
+ int lexer_ignorechar;
+ int expression;
+ int parser_state;
+
+ void *input_state;
+
+ char *currentsub;
+ symtab_t *global_syms;
+ symtab_t *local_syms;
+ int returntype;
+ int framesize;
+} cstate;
+
+/* parser states */
+enum
+{
+ parser_state_global = 0, /* only global decls allowed */
+ parser_state_error
+};
+
+/* token types */
+enum
+{
+ token_kw_sub, /* SUB keyword */
+ token_kw_function, /* FUNCTION keyword */
+ token_kw_as, /* AS keyword */
+ token_kw_public, /* PUBLIC keyword */
+ token_kw_private, /* PRIVATE keyword */
+ token_kw_params, /* PARAMS keyword */
+ token_kw_returns, /* RETURNS keyword */
+ token_kw_integer, /* INTEGER keyword */
+ token_kw_endsub, /* ENDSUB keyword */
+ token_kw_endfunction, /* ENDFUNCTION keyword */
+ token_kw_dim, /* DIM keyword */
+ token_op_assignment, /* assignment operator */
+ token_op_equality, /* equality test */
+ token_op_greater, /* greater than */
+ token_op_less, /* less than */
+ token_op_greaterequal, /* greater or equal */
+ token_op_lessequal, /* less or equal */
+ token_op_notequal, /* not equal */
+ token_op_and, /* boolean and */
+ token_op_or, /* boolean or */
+ token_op_xor, /* boolean exlusive or */
+ token_op_band, /* bitwise and */
+ token_op_bor, /* bitwise or */
+ token_op_bxor, /* bitwise xor */
+ token_op_plus, /* plus */
+ token_op_minus, /* minus */
+ token_op_times, /* times */
+ token_op_divide, /* divide */
+ token_op_modulus, /* modulus */
+ token_op_oparen, /* open paren */
+ token_op_cparen, /* close paren */
+ token_op_not, /* boolean not */
+ token_op_bnot, /* bitwise not */
+ token_identifier, /* an identifier (variable, function, etc. */
+ token_char, /* single character; fallback */
+ token_uint, /* unsigned integer up to 32 bits */
+ token_int, /* signed integer up to 32 bits */
+ token_eol, /* end of line */
+ token_eof /* end of file */
+};
+
+/* symbol types */
+enum
+{
+ symtype_sub, /* "sub" (void function) */
+ symtype_func, /* function (nonvoid) */
+ symtype_param, /* function parameter */
+ symtype_var /* variable */
+};
+
+#ifndef __input_c_seen__
+extern int input_getchar(cstate *state);
+#endif
+
+#ifndef __main_c_seen__
+extern void lwb_error(const char *fmt, ...);
+#endif
+
+#ifndef __lexer_c_seen__
+extern void lexer(cstate *state);
+extern char *lexer_return_token(cstate *state);
+extern char *lexer_token_name(int token);
+#endif
+
+#ifndef __emit_c_seen__
+extern void emit_prolog(cstate *state, int vis);
+extern void emit_epilog(cstate *state);
+#endif
+
+
+#endif /* __lwbasic_h_seen__ */
diff -r 6433cb024174 -r cca933d32298 lwbasic/attic/main.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwbasic/attic/main.c Thu Dec 22 18:03:38 2011 -0700
@@ -0,0 +1,117 @@
+/*
+main.c
+
+Copyright © 2011 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 of the License, or (at your option) any later
+version.
+
+This program 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, see .
+*/
+
+/*
+main program startup handling for lwbasic
+*/
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#define __main_c_seen__
+#include "lwbasic.h"
+
+#define PROGVER "lwbasic from " PACKAGE_STRING
+
+static struct lw_cmdline_options options[] =
+{
+ { "output", 'o', "FILE", 0, "Output to FILE"},
+ { "debug", 'd', "LEVEL", lw_cmdline_opt_optional, "Set debug mode"},
+ { 0 }
+};
+
+static int parse_opts(int key, char *arg, void *data)
+{
+ cstate *state = data;
+
+ switch (key)
+ {
+ case 'o':
+ if (state -> output_file)
+ lw_free(state -> output_file);
+ state -> output_file = lw_strdup(arg);
+ break;
+
+ case 'd':
+ if (!arg)
+ state -> debug_level = 50;
+ else
+ state -> debug_level = atoi(arg);
+ break;
+
+ case lw_cmdline_key_end:
+ return 0;
+
+ case lw_cmdline_key_arg:
+ if (state -> input_file)
+ {
+ fprintf(stderr, "Already have an input file; ignoring %s\n", arg);
+ }
+ else
+ {
+ state -> input_file = lw_strdup(arg);
+ }
+ break;
+
+ default:
+ return lw_cmdline_err_unknown;
+ }
+
+ return 0;
+}
+
+static struct lw_cmdline_parser cmdline_parser =
+{
+ options,
+ parse_opts,
+ "INPUTFILE",
+ "lwbasic, a compiler for a dialect of Basic\vPlease report bugs to lost@l-w.ca.",
+ PROGVER
+};
+
+extern void parser(cstate *state);
+
+int main(int argc, char **argv)
+{
+ cstate state = { 0 };
+
+ lw_cmdline_parse(&cmdline_parser, argc, argv, 0, 0, &state);
+
+ parser(&state);
+
+ exit(0);
+}
+
+void lwb_error(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ exit(1);
+}
diff -r 6433cb024174 -r cca933d32298 lwbasic/attic/parser.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwbasic/attic/parser.c Thu Dec 22 18:03:38 2011 -0700
@@ -0,0 +1,469 @@
+/*
+compiler.c
+
+Copyright © 2011 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 of the License, or (at your option) any later
+version.
+
+This program 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, see .
+*/
+
+/*
+This is the actual compiler bit; it drives the parser and code generation
+*/
+
+#include
+
+#include
+#include
+
+#include "lwbasic.h"
+#include "symtab.h"
+
+static void expect(cstate *state, int tt)
+{
+ if (state -> lexer_token != tt)
+ lwb_error("Expecting %s, got %s\n", lexer_token_name(tt), lexer_return_token(state));
+ lexer(state);
+}
+
+
+/* size of a type */
+static int sizeof_type(int type)
+{
+ /* everything is an "int" right now; 2 bytes */
+ return 2;
+}
+
+/* parse a type; the next token will be acquired as a result */
+/* the token advancement is to provide consistency */
+static int parse_type(cstate *state)
+{
+ int pt = -1;
+
+ switch (state -> lexer_token)
+ {
+ case token_kw_integer:
+ pt = 1;
+ break;
+
+ default:
+ lwb_error("Invalid type specification");
+ }
+ lexer(state);
+ /* look for "unsigned" modifier for integer types */
+ return pt;
+}
+
+static void parse_expr(cstate *state, int prec);
+static void parse_term(cstate *state);
+static int parse_expression(cstate *state)
+{
+ state -> expression = 1;
+
+ parse_expr(state, 0);
+
+ state -> expression = 0;
+ return 1;
+}
+
+static void parse_decls(cstate *state)
+{
+ /* declarations */
+ /* the first thing that doesn't look like a declaration is assumed */
+ /* to be a statement and will trigger a bailout */
+ int vt;
+ char *vn;
+ symtab_entry_t *se;
+
+ for (;;)
+ {
+ switch (state -> lexer_token)
+ {
+ /* DIM keyword */
+ case token_kw_dim:
+ lexer(state);
+ if (state -> lexer_token != token_identifier)
+ {
+ lwb_error("Expecting identifier, got %s\n", lexer_return_token(state));
+ }
+ vn = lw_strdup(state -> lexer_token_string);
+ lexer(state);
+ if (state -> lexer_token != token_kw_as)
+ {
+ lwb_error("Expecting AS, got %s\n", lexer_return_token(state));
+ }
+ lexer(state);
+ vt = parse_type(state);
+
+ se = symtab_find(state -> local_syms, vn);
+ if (se)
+ {
+ lwb_error("Multiply defined local variable %s", vn);
+ }
+ state -> framesize += sizeof_type(vt);
+ symtab_register(state -> local_syms, vn, -(state -> framesize), symtype_var, NULL);
+
+ lw_free(vn);
+ break;
+
+ /* blank lines allowed */
+ case token_eol:
+ break;
+
+ default:
+ return;
+ }
+ if (state -> lexer_token != token_eol)
+ lwb_error("Expecting end of line; got %s\n", lexer_return_token(state));
+ lexer(state);
+ }
+}
+
+static void parse_statements(cstate *state)
+{
+ symtab_entry_t *se;
+ int et;
+
+ for (;;)
+ {
+ switch (state -> lexer_token)
+ {
+ /* blank lines allowed */
+ case token_eol:
+ break;
+
+ /* variable assignment */
+ case token_identifier:
+ se = symtab_find(state -> local_syms, state -> lexer_token_string);
+ if (!se)
+ {
+ se = symtab_find(state -> global_syms, state -> lexer_token_string);
+ }
+ if (!se)
+ lwb_error("Unknown variable %s\n", state -> lexer_token_string);
+ lexer(state);
+ /* ensure the first token of the expression will be parsed correctly */
+ state -> expression = 1;
+ expect(state, token_op_assignment);
+
+ /* parse the expression */
+ et = parse_expression(state);
+
+ /* check type compatibility */
+
+ /* actually do the assignment */
+
+ break;
+
+ /* anything we don't recognize as a statement token breaks out */
+ default:
+ return;
+ }
+ if (state -> lexer_token != token_eol)
+ lwb_error("Expecting end of line; got %s\n", lexer_return_token(state));
+ lexer(state);
+ }
+}
+
+
+/* issub means RETURNS is not allowed; !issub means RETURNS is required */
+
+static void parse_subfunc(cstate *state, int issub)
+{
+ int pt, rt;
+ char *subname, *pn;
+ int vis = 0;
+ symtab_entry_t *se;
+ int paramsize = 0;
+
+ state -> local_syms = symtab_init();
+ state -> framesize = 0;
+
+ lexer(state);
+ if (state -> lexer_token != token_identifier)
+ {
+ lwb_error("Invalid sub name '%s'", state -> lexer_token_string);
+ }
+
+ subname = lw_strdup(state -> lexer_token_string);
+
+ lexer(state);
+ if (state -> lexer_token == token_kw_public || state -> lexer_token == token_kw_private)
+ {
+ if (state -> lexer_token == token_kw_public)
+ vis = 1;
+ lexer(state);
+ }
+
+ /* ignore the "PARAMS" keyword if present */
+ if (state -> lexer_token == token_kw_params)
+ lexer(state);
+
+ if (state -> lexer_token == token_eol || state -> lexer_token == token_kw_returns)
+ goto noparms;
+
+paramagain:
+ if (state -> lexer_token != token_identifier)
+ {
+ lwb_error("Parameter name expected, got %s\n", lexer_return_token(state));
+ }
+ pn = lw_strdup(state -> lexer_token_string);
+ lexer(state);
+
+ if (state -> lexer_token != token_kw_as)
+ lwb_error("Expecting AS\n");
+ lexer(state);
+
+ pt = parse_type(state);
+
+ se = symtab_find(state -> local_syms, pn);
+ if (se)
+ {
+ lwb_error("Duplicate parameter name %s\n", pn);
+ }
+ symtab_register(state -> local_syms, pn, paramsize, symtype_param, NULL);
+ paramsize += sizeof_type(pt);
+ lw_free(pn);
+
+ if (state -> lexer_token == token_char && state -> lexer_token_string[0] == ',')
+ {
+ lexer(state);
+ goto paramagain;
+ }
+
+noparms:
+ rt = -1;
+ if (!issub)
+ {
+ if (state -> lexer_token != token_kw_returns)
+ {
+ lwb_error("FUNCTION must have RETURNS\n");
+ }
+ lexer(state);
+/* if (state -> lexer_token == token_identifier)
+ {
+ printf("Return value named: %s\n", state -> lexer_token_string);
+
+ lexer(state);
+ if (state -> lexer_token != token_kw_as)
+ lwb_error("Execting AS after RETURNS");
+ lexer(state);
+ }
+*/
+ rt = parse_type(state);
+ }
+ else
+ {
+ if (state -> lexer_token == token_kw_returns)
+ {
+ lwb_error("SUB cannot specify RETURNS\n");
+ }
+ }
+
+
+ if (state -> lexer_token != token_eol)
+ {
+ lwb_error("EOL expected; found %s\n", lexer_return_token(state));
+ }
+
+
+ se = symtab_find(state -> global_syms, subname);
+ if (se)
+ {
+ lwb_error("Multiply defined symbol %s\n", subname);
+ }
+
+ symtab_register(state -> global_syms, subname, -1, issub ? symtype_sub : symtype_func, NULL);
+
+ state -> currentsub = subname;
+ state -> returntype = rt;
+ /* consume EOL */
+ lexer(state);
+
+ /* variable declarations */
+ parse_decls(state);
+
+ /* output function/sub prolog */
+ emit_prolog(state, vis);
+
+ /* parse statement block */
+ parse_statements(state);
+
+ if (issub)
+ {
+ if (state -> lexer_token != token_kw_endsub)
+ {
+ lwb_error("Expecting ENDSUB, got %s\n", lexer_return_token(state));
+ }
+ }
+ else
+ {
+ if (state -> lexer_token != token_kw_endfunction)
+ {
+ lwb_error("Expecting ENDFUNCTION, got %s\n", lexer_return_token(state));
+ }
+ }
+ /* output function/sub epilog */
+ emit_epilog(state);
+
+ lw_free(state -> currentsub);
+ state -> currentsub = NULL;
+ symtab_destroy(state -> local_syms);
+ state -> local_syms = NULL;
+}
+
+void parser(cstate *state)
+{
+ state -> lexer_curchar = -1;
+ state -> global_syms = symtab_init();
+
+ /* now look for a global declaration */
+ for (;;)
+ {
+ state -> parser_state = parser_state_global;
+ lexer(state);
+ switch (state -> lexer_token)
+ {
+ case token_kw_function:
+ printf("Function\n");
+ parse_subfunc(state, 0);
+ break;
+
+ case token_kw_sub:
+ printf("Sub\n");
+ parse_subfunc(state, 1);
+ break;
+
+ /* blank lines are allowed */
+ case token_eol:
+ continue;
+
+ /* EOF is allowed - end of parsing */
+ case token_eof:
+ return;
+
+ default:
+ lwb_error("Invalid token '%s' in global state\n", lexer_return_token(state));
+ }
+ }
+}
+
+static void parse_expr(cstate *state, int prec)
+{
+ static const struct operinfo {
+ int opernum;
+ int operprec;
+ } operators[] =
+ {
+ { token_op_plus, 100 },
+ { token_op_minus, 100 },
+ { token_op_times, 150 },
+ { token_op_divide, 150 },
+ { token_op_modulus, 150 },
+ { token_op_and, 25 },
+ { token_op_or, 20 },
+ { token_op_xor, 20 },
+ { token_op_band, 50 },
+ { token_op_bor, 45 },
+ { token_op_bxor, 45 },
+ { -1, -1 }
+ };
+ int opern;
+
+ parse_term(state);
+
+eval_next:
+ for (opern = 0; operators[opern].opernum != -1; opern++)
+ {
+ if (operators[opern].opernum == state -> lexer_token)
+ break;
+ }
+ if (operators[opern].opernum == -1)
+ return;
+
+ if (operators[opern].operprec <= prec)
+ return;
+
+ lexer(state);
+
+ parse_expr(state, operators[opern].operprec);
+
+ /* push operator */
+
+ goto eval_next;
+}
+
+static void parse_term(cstate *state)
+{
+eval_next:
+ /* parens */
+ if (state -> lexer_token == token_op_oparen)
+ {
+ lexer(state);
+ parse_expr(state, 0);
+ expect(state, token_op_cparen);
+ return;
+ }
+
+ /* unary plus; ignore it */
+ if (state -> lexer_token == token_op_plus)
+ {
+ lexer(state);
+ goto eval_next;
+ }
+
+ /* unary minus, precision 200 */
+ if (state -> lexer_token == token_op_minus)
+ {
+ lexer(state);
+ parse_expr(state, 200);
+
+ /* push unary negation */
+ }
+
+ /* BNOT, NOT */
+ if (state -> lexer_token == token_op_not || state -> lexer_token == token_op_bnot)
+ {
+ lexer(state);
+ parse_expr(state, 200);
+
+ /* push unary operator */
+ }
+
+ /* integer */
+ if (state -> lexer_token == token_int)
+ {
+ }
+
+ /* unsigned integer */
+ if (state -> lexer_token == token_uint)
+ {
+ }
+
+ /* variable or function call */
+ if (state -> lexer_token == token_identifier)
+ {
+ lexer(state);
+ if (state -> lexer_token == token_op_oparen)
+ {
+ /* function call */
+ return;
+ }
+ /* variable */
+ return;
+ }
+
+ lwb_error("Invalid input in expression; got %s\n", lexer_return_token(state));
+}
diff -r 6433cb024174 -r cca933d32298 lwbasic/attic/rules.make
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwbasic/attic/rules.make Thu Dec 22 18:03:38 2011 -0700
@@ -0,0 +1,28 @@
+dirname := $(dir $(lastword $(MAKEFILE_LIST)))
+lwbasic_dir := $(dirname)
+
+lwbasic_lsrcs := main.c input.c parser.c lexer.c emit.c symtab.c
+
+lwbasic_srcs := $(addprefix $(dirname),$(lwbasic_lsrcs))
+lwbasic_objs := $(lwbasic_srcs:.c=.o)
+lwbasic_deps := $(lwbasic_srcs:.c=.d)
+
+
+
+$(lwbasic_dir)lwbasic$(PROGSUFFIX): $(lwbasic_objs) lwlib $(lwbasic_dir)rules.make
+ @echo "Linking $@"
+ @$(CC) -o $@ $(lwbasic_objs) $(LDFLAGS)
+
+cleantargs := $(cleantargs) lwbasicclean
+realcleantargs := $(realcleantargs) lwbasicrealclean
+
+.PHONY: lwbasicclean lwbasicrealclean
+lwbasicrealclean:
+ @echo "Really cleaning up lwbasic"
+ @cd $(lwbasic_dir) && rm -f *.d
+
+lwbasicclean:
+ @echo "Cleaning up lwbasic"
+ @cd $(lwbasic_dir) && rm -f *.o *.exe lwbasic
+
+-include $(lwbasic_deps)
diff -r 6433cb024174 -r cca933d32298 lwbasic/attic/symtab.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwbasic/attic/symtab.c Thu Dec 22 18:03:38 2011 -0700
@@ -0,0 +1,82 @@
+/*
+symtab.c
+
+Copyright © 2011 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 of the License, or (at your option) any later
+version.
+
+This program 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, see .
+*/
+
+/*
+Symbol table handling
+*/
+
+#include
+#include
+
+#include
+#include
+
+#define __symtab_c_seen__
+#include "symtab.h"
+
+symtab_t *symtab_init(void)
+{
+ symtab_t *st;
+
+ st = lw_alloc(sizeof(symtab_t));
+ st -> head = NULL;
+ return st;
+}
+
+void symtab_destroy(symtab_t *st)
+{
+ symtab_entry_t *se;
+
+ while (st -> head)
+ {
+ se = st -> head;
+ st -> head = se -> next;
+ lw_free(se -> name);
+ lw_free(se -> privdata);
+ lw_free(se);
+ }
+ lw_free(st);
+}
+
+symtab_entry_t *symtab_find(symtab_t *st, char *name)
+{
+ symtab_entry_t *se;
+
+ for (se = st -> head; se; se = se -> next)
+ {
+ if (strcmp(se -> name, name) == 0)
+ return se;
+ }
+ return NULL;
+}
+
+void symtab_register(symtab_t *st, char *name, int addr, int symtype, void *privdata)
+{
+ symtab_entry_t *se;
+
+ se = lw_alloc(sizeof(symtab_entry_t));
+ se -> name = lw_strdup(name);
+ se -> addr = addr;
+ se -> symtype = symtype;
+ se -> privdata = privdata;
+ se -> next = st -> head;
+ st -> head = se;
+}
diff -r 6433cb024174 -r cca933d32298 lwbasic/emit.c
--- a/lwbasic/emit.c Thu Dec 22 18:03:04 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
-emit.c
-
-Copyright © 2011 William Astle
-
-This file is part of LWTOOLS.
-
-LWTOOLS 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 3 of the License, or (at your option) any later
-version.
-
-This program 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, see .
-*/
-
-/*
-This is the actual compiler bit; it drives the parser and code generation
-*/
-
-#include
-
-#define __emit_c_seen__
-#include "lwbasic.h"
-
-void emit_prolog(cstate *state, int vis)
-{
- if (vis)
- {
- printf("\texport _%s\n", state -> currentsub);
- }
- printf("_%s\n", state -> currentsub);
- if (state -> framesize > 0)
- {
- printf("\tleas %d,s\n", -(state -> framesize));
- }
-}
-
-void emit_epilog(cstate *state)
-{
- if (state -> framesize > 0)
- {
- printf("\tleas %d,s\n", state -> framesize);
- }
- printf("\trts\n");
-}
diff -r 6433cb024174 -r cca933d32298 lwbasic/input.c
--- a/lwbasic/input.c Thu Dec 22 18:03:04 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
-input.c
-
-Copyright © 2011 William Astle
-
-This file is part of LWTOOLS.
-
-LWTOOLS 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 3 of the License, or (at your option) any later
-version.
-
-This program 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, see .
-*/
-
-/*
-handle reading input for the rest of the system
-*/
-
-#include
-#include
-#include
-
-#include
-#include
-
-#define __input_c_seen__
-#include "lwbasic.h"
-
-struct input_state
-{
- FILE *fp;
- int error;
-};
-
-static void input_init(cstate *state)
-{
- struct input_state *sp;
-
- sp = lw_alloc(sizeof(struct input_state));
- sp -> error = 0;
-
- if (!(state -> input_file) || strcmp(state -> input_file, "-"))
- {
- sp -> fp = stdin;
- }
- else
- {
- sp -> fp = fopen(state -> input_file, "rb");
- if (!(sp -> fp))
- {
- lwb_error("Cannot open input file\n");
- }
- }
-
- state -> input_state = sp;
-}
-
-int input_getchar(cstate *state)
-{
- int r;
- struct input_state *sp;
-
- if (!(state -> input_state))
- input_init(state);
- sp = state -> input_state;
-
-
- if (sp -> error)
- return -2;
-
- if (feof(sp -> fp))
- return -1;
-
- r = fgetc(sp -> fp);
- if (r == EOF)
- return -1;
- return r;
-}
diff -r 6433cb024174 -r cca933d32298 lwbasic/lexer.c
--- a/lwbasic/lexer.c Thu Dec 22 18:03:04 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,440 +0,0 @@
-/*
-lexer.c
-
-Copyright © 2011 William Astle
-
-This file is part of LWTOOLS.
-
-LWTOOLS 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 3 of the License, or (at your option) any later
-version.
-
-This program 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, see .
-*/
-
-/*
-This handles the gritty details of parsing tokens
-*/
-
-#include
-#include
-#include
-
-#include
-#include
-
-#define __lexer_c_seen__
-#include "lwbasic.h"
-
-/*
-A token idenfier is returned by lexer(). The actual string value
-is found in state->lexer_lexer_token_string; if the token as an integer value,
-it will be found in state->lexer_token_number in the appropriate "value"
-slot.
-*/
-
-struct token_list
-{
- char *string;
- int token;
-};
-
-/* keywords that appear as part of normal expressions */
-static struct token_list lexer_global_tokens[] =
-{
- { "function", token_kw_function },
- { "sub", token_kw_sub },
- { "public", token_kw_public },
- { "private", token_kw_private },
- { "as", token_kw_as },
- { "params", token_kw_params },
- { "returns", token_kw_returns },
- { "integer", token_kw_integer },
- { "endsub", token_kw_endsub },
- { "endfunction", token_kw_endfunction },
- { "dim", token_kw_dim },
- { NULL }
-};
-
-/* contains "built in" function names */
-static struct token_list lexer_expr_tokens[] =
-{
- { "and", token_op_and },
- { "or", token_op_or },
- { "band", token_op_band },
- { "bor", token_op_bor },
- { "bxor", token_op_bxor },
- { "xor", token_op_xor },
- { "not", token_op_not },
- { "bnot", token_op_bnot },
- { NULL }
-};
-
-static char *lexer_token_names[] =
-{
- "SUB",
- "FUNCTION",
- "AS",
- "PUBLIC",
- "PRIVATE",
- "PARAMS",
- "RETURNS",
- "INTEGER",
- "ENDSUB",
- "ENDFUNCTION",
- "DIM",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- ""
-};
-
-char *lexer_token_name(int token)
-{
- if (token > token_eol)
- return "???";
- return lexer_token_names[token];
-}
-
-static int lexer_getchar(cstate *state)
-{
- int c;
- c = input_getchar(state);
- if (c == -2)
- {
- lwb_error("Error reading input stream.");
- }
- return c;
-}
-
-static void lexer_nextchar(cstate *state)
-{
- state -> lexer_curchar = lexer_getchar(state);
- if (state -> lexer_curchar == state -> lexer_ignorechar)
- state -> lexer_curchar = lexer_getchar(state);
- state -> lexer_ignorechar = 0;
-}
-
-static int lexer_curchar(cstate *state)
-{
- if (state -> lexer_curchar == -1)
- {
- lexer_nextchar(state);
- }
-
- return state -> lexer_curchar;
-}
-
-static void lexer_skip_white(cstate *state)
-{
- int c;
-
- for (;;)
- {
- c = lexer_curchar(state);
- if (!(c == 0 || c == ' ' || c == '\t'))
- return;
- lexer_nextchar(state);
- }
-}
-
-/* must not be called unless the word will be non-zero length */
-static void lexer_word(cstate *state)
-{
- int wordlen = 0;
- int wordpos = 0;
- char *word = NULL;
- int c;
- struct token_list *tok = NULL;
-
- for (;;) {
- c = lexer_curchar(state);
- if (c == '_' || (c >= '0' && c <= '9' ) || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c >= 0x80)
- {
- /* character is part of word */
- if (wordpos >= wordlen)
- {
- word = lw_realloc(word, wordlen + 32);
- wordlen += 32;
- }
- word[wordpos++] = c;
- }
- else
- break;
-
- lexer_nextchar(state);
- }
-
- word[wordpos] = 0;
- lw_free(state -> lexer_token_string);
- state -> lexer_token_string = lw_strdup(word);
-
- switch (state -> parser_state)
- {
- default:
- tok = lexer_global_tokens;
- }
-
- if (state -> expression)
- {
- tok = lexer_expr_tokens;
- }
-
- /* check for tokens if appropriate */
- /* force uppercase */
- if (tok)
- {
- for (c = 0; word[c]; c++)
- if (word[c] >= 'A' && word[c] <= 'Z')
- word[c] = word[c] + 0x20;
-
- while (tok -> string)
- {
- if (strcmp(tok -> string, word) == 0)
- break;
- tok++;
- }
- }
-
- lw_free(word);
- if (tok && tok -> string)
- state -> lexer_token = tok -> token;
- else
- state -> lexer_token = token_identifier;
-}
-
-static void lexer_parse_number(cstate *state, int neg)
-{
- unsigned long tint = 0;
- int c;
-
- for (;;)
- {
- c = lexer_curchar(state);
- if (c >= '0' && c <= '9')
- {
- tint *= 10 + (c - '0');
- }
- else
- {
- /* end of the number here */
- if (neg)
- {
- if (tint > 0x80000000)
- lwb_error("Integer overflow\n");
- state -> lexer_token_number.integer = -tint;
- state -> lexer_token = token_int;
- }
- else
- {
- state -> lexer_token = token_uint;
- state -> lexer_token_number.uinteger = tint;
- }
- return;
- }
- lexer_nextchar(state);
- }
-}
-
-static void lexer_empty_token(cstate *state)
-{
- lw_free(state -> lexer_token_string);
- state -> lexer_token_string = NULL;
-}
-
-void lexer(cstate *state)
-{
- int c;
-
- lexer_skip_white(state);
-
- lexer_empty_token(state);
-
- c = lexer_curchar(state);
- if (c == -1)
- {
- state -> lexer_token = token_eof;
- return;
- }
-
- if (c == '\n')
- {
- /* LF */
- lexer_nextchar(state);
- state -> lexer_ignorechar = '\r';
- state -> lexer_token = token_eol;
- return;
- }
-
- if (c == '\r')
- {
- /* CR */
- lexer_nextchar(state);
- state -> lexer_ignorechar = '\n';
- state -> lexer_token = token_eol;
- return;
- }
-
- if (c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c >= 0x80)
- {
- /* we have a word here; identifier, keyword, etc. */
- lexer_word(state);
- return;
- }
-
- if (state -> expression && c >= '0' && c <= '9')
- {
- /* we have a number */
- lexer_parse_number(state, 0);
- return;
- }
-
- lexer_nextchar(state);
- if (state -> expression)
- {
- if (c == '-' && lexer_curchar(state) >= '0' && lexer_curchar(state) <= '9')
- {
- /* we have a negative number here */
- lexer_parse_number(state, 1);
- return;
- }
- if (c == '=')
- {
- state -> lexer_token = token_op_equality;
- return;
- }
- if (c == '<')
- {
- if (lexer_curchar(state) == '=')
- {
- lexer_nextchar(state);
- state -> lexer_token = token_op_lessequal;
- return;
- }
- if (lexer_curchar(state) == '>')
- {
- lexer_nextchar(state);
- state -> lexer_token = token_op_notequal;
- return;
- }
- state -> lexer_token = token_op_less;
- return;
- }
- if (c == '>')
- {
- if (lexer_curchar(state) == '>')
- {
- lexer_nextchar(state);
- state -> lexer_token = token_op_greaterequal;
- return;
- }
- if (lexer_curchar(state) == '<')
- {
- state -> lexer_token = token_op_notequal;
- lexer_nextchar(state);
- return;
- }
- state -> lexer_token = token_op_greater;
- return;
- }
- switch(c)
- {
- case '+':
- state -> lexer_token = token_op_plus;
- return;
-
- case '-':
- state -> lexer_token = token_op_minus;
- return;
-
- case '/':
- state -> lexer_token = token_op_divide;
- return;
-
- case '*':
- state -> lexer_token = token_op_times;
- return;
-
- case '%':
- state -> lexer_token = token_op_modulus;
- return;
-
- case '(':
- state -> lexer_token = token_op_oparen;
- return;
-
- case ')':
- state -> lexer_token = token_op_cparen;
- return;
-
- }
- }
- else
- {
- if (c == '=')
- {
- state -> lexer_token = token_op_assignment;
- return;
- }
- }
-
- /* return the character if all else fails */
- state -> lexer_token = token_char;
- state -> lexer_token_string = lw_realloc(state -> lexer_token_string, 2);
- state -> lexer_token_string[0] = c;
- state -> lexer_token_string[1] = 0;
- return;
-}
-
-char *lexer_return_token(cstate *state)
-{
- static char *buffer = NULL;
- static int buflen = 0;
- int l;
-
- if (buflen == 0)
- {
- buffer = lw_alloc(128);
- buflen = 128;
- }
-
- l = snprintf(buffer, buflen, "%s (%s)", state -> lexer_token_string, lexer_token_name(state -> lexer_token));
- if (l >= buflen)
- {
- buffer = lw_realloc(buffer, l + 1);
- buflen = l + 1;
- snprintf(buffer, buflen, "%s (%s)", state -> lexer_token_string, lexer_token_name(state -> lexer_token));
- }
- return buffer;
-}
diff -r 6433cb024174 -r cca933d32298 lwbasic/lwbasic.h
--- a/lwbasic/lwbasic.h Thu Dec 22 18:03:04 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/*
-lwbasic.h
-
-Copyright © 2011 William Astle
-
-This file is part of LWTOOLS.
-
-LWTOOLS 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 3 of the License, or (at your option) any later
-version.
-
-This program 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, see .
-*/
-
-/*
-definitions used throughout lwbasic
-*/
-
-#ifndef __lwbasic_h_seen__
-#define __lwbasic_h_seen__
-
-#include
-
-#include "symtab.h"
-
-/* note: integer and uinteger will be the same for positive values from 0
-through 0x7FFFFFFF; the unsigned type should be used for doing ascii
-conversions and then if a negative value was discovered, it should be
-negated IFF it is in range. */
-
-union lexer_numbers
-{
- uint32_t uinteger;
- int32_t integer;
-};
-
-typedef struct
-{
- char *output_file;
- char *input_file;
-
- int debug_level;
-
- char *lexer_token_string;
- union lexer_numbers lexer_token_number;
- int lexer_token;
- int lexer_curchar;
- int lexer_ignorechar;
- int expression;
- int parser_state;
-
- void *input_state;
-
- char *currentsub;
- symtab_t *global_syms;
- symtab_t *local_syms;
- int returntype;
- int framesize;
-} cstate;
-
-/* parser states */
-enum
-{
- parser_state_global = 0, /* only global decls allowed */
- parser_state_error
-};
-
-/* token types */
-enum
-{
- token_kw_sub, /* SUB keyword */
- token_kw_function, /* FUNCTION keyword */
- token_kw_as, /* AS keyword */
- token_kw_public, /* PUBLIC keyword */
- token_kw_private, /* PRIVATE keyword */
- token_kw_params, /* PARAMS keyword */
- token_kw_returns, /* RETURNS keyword */
- token_kw_integer, /* INTEGER keyword */
- token_kw_endsub, /* ENDSUB keyword */
- token_kw_endfunction, /* ENDFUNCTION keyword */
- token_kw_dim, /* DIM keyword */
- token_op_assignment, /* assignment operator */
- token_op_equality, /* equality test */
- token_op_greater, /* greater than */
- token_op_less, /* less than */
- token_op_greaterequal, /* greater or equal */
- token_op_lessequal, /* less or equal */
- token_op_notequal, /* not equal */
- token_op_and, /* boolean and */
- token_op_or, /* boolean or */
- token_op_xor, /* boolean exlusive or */
- token_op_band, /* bitwise and */
- token_op_bor, /* bitwise or */
- token_op_bxor, /* bitwise xor */
- token_op_plus, /* plus */
- token_op_minus, /* minus */
- token_op_times, /* times */
- token_op_divide, /* divide */
- token_op_modulus, /* modulus */
- token_op_oparen, /* open paren */
- token_op_cparen, /* close paren */
- token_op_not, /* boolean not */
- token_op_bnot, /* bitwise not */
- token_identifier, /* an identifier (variable, function, etc. */
- token_char, /* single character; fallback */
- token_uint, /* unsigned integer up to 32 bits */
- token_int, /* signed integer up to 32 bits */
- token_eol, /* end of line */
- token_eof /* end of file */
-};
-
-/* symbol types */
-enum
-{
- symtype_sub, /* "sub" (void function) */
- symtype_func, /* function (nonvoid) */
- symtype_param, /* function parameter */
- symtype_var /* variable */
-};
-
-#ifndef __input_c_seen__
-extern int input_getchar(cstate *state);
-#endif
-
-#ifndef __main_c_seen__
-extern void lwb_error(const char *fmt, ...);
-#endif
-
-#ifndef __lexer_c_seen__
-extern void lexer(cstate *state);
-extern char *lexer_return_token(cstate *state);
-extern char *lexer_token_name(int token);
-#endif
-
-#ifndef __emit_c_seen__
-extern void emit_prolog(cstate *state, int vis);
-extern void emit_epilog(cstate *state);
-#endif
-
-
-#endif /* __lwbasic_h_seen__ */
diff -r 6433cb024174 -r cca933d32298 lwbasic/main.c
--- a/lwbasic/main.c Thu Dec 22 18:03:04 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
-main.c
-
-Copyright © 2011 William Astle
-
-This file is part of LWTOOLS.
-
-LWTOOLS 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 3 of the License, or (at your option) any later
-version.
-
-This program 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, see .
-*/
-
-/*
-main program startup handling for lwbasic
-*/
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#define __main_c_seen__
-#include "lwbasic.h"
-
-#define PROGVER "lwbasic from " PACKAGE_STRING
-
-static struct lw_cmdline_options options[] =
-{
- { "output", 'o', "FILE", 0, "Output to FILE"},
- { "debug", 'd', "LEVEL", lw_cmdline_opt_optional, "Set debug mode"},
- { 0 }
-};
-
-static int parse_opts(int key, char *arg, void *data)
-{
- cstate *state = data;
-
- switch (key)
- {
- case 'o':
- if (state -> output_file)
- lw_free(state -> output_file);
- state -> output_file = lw_strdup(arg);
- break;
-
- case 'd':
- if (!arg)
- state -> debug_level = 50;
- else
- state -> debug_level = atoi(arg);
- break;
-
- case lw_cmdline_key_end:
- return 0;
-
- case lw_cmdline_key_arg:
- if (state -> input_file)
- {
- fprintf(stderr, "Already have an input file; ignoring %s\n", arg);
- }
- else
- {
- state -> input_file = lw_strdup(arg);
- }
- break;
-
- default:
- return lw_cmdline_err_unknown;
- }
-
- return 0;
-}
-
-static struct lw_cmdline_parser cmdline_parser =
-{
- options,
- parse_opts,
- "INPUTFILE",
- "lwbasic, a compiler for a dialect of Basic\vPlease report bugs to lost@l-w.ca.",
- PROGVER
-};
-
-extern void parser(cstate *state);
-
-int main(int argc, char **argv)
-{
- cstate state = { 0 };
-
- lw_cmdline_parse(&cmdline_parser, argc, argv, 0, 0, &state);
-
- parser(&state);
-
- exit(0);
-}
-
-void lwb_error(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
-
- exit(1);
-}
diff -r 6433cb024174 -r cca933d32298 lwbasic/parser.c
--- a/lwbasic/parser.c Thu Dec 22 18:03:04 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,469 +0,0 @@
-/*
-compiler.c
-
-Copyright © 2011 William Astle
-
-This file is part of LWTOOLS.
-
-LWTOOLS 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 3 of the License, or (at your option) any later
-version.
-
-This program 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, see .
-*/
-
-/*
-This is the actual compiler bit; it drives the parser and code generation
-*/
-
-#include
-
-#include
-#include
-
-#include "lwbasic.h"
-#include "symtab.h"
-
-static void expect(cstate *state, int tt)
-{
- if (state -> lexer_token != tt)
- lwb_error("Expecting %s, got %s\n", lexer_token_name(tt), lexer_return_token(state));
- lexer(state);
-}
-
-
-/* size of a type */
-static int sizeof_type(int type)
-{
- /* everything is an "int" right now; 2 bytes */
- return 2;
-}
-
-/* parse a type; the next token will be acquired as a result */
-/* the token advancement is to provide consistency */
-static int parse_type(cstate *state)
-{
- int pt = -1;
-
- switch (state -> lexer_token)
- {
- case token_kw_integer:
- pt = 1;
- break;
-
- default:
- lwb_error("Invalid type specification");
- }
- lexer(state);
- /* look for "unsigned" modifier for integer types */
- return pt;
-}
-
-static void parse_expr(cstate *state, int prec);
-static void parse_term(cstate *state);
-static int parse_expression(cstate *state)
-{
- state -> expression = 1;
-
- parse_expr(state, 0);
-
- state -> expression = 0;
- return 1;
-}
-
-static void parse_decls(cstate *state)
-{
- /* declarations */
- /* the first thing that doesn't look like a declaration is assumed */
- /* to be a statement and will trigger a bailout */
- int vt;
- char *vn;
- symtab_entry_t *se;
-
- for (;;)
- {
- switch (state -> lexer_token)
- {
- /* DIM keyword */
- case token_kw_dim:
- lexer(state);
- if (state -> lexer_token != token_identifier)
- {
- lwb_error("Expecting identifier, got %s\n", lexer_return_token(state));
- }
- vn = lw_strdup(state -> lexer_token_string);
- lexer(state);
- if (state -> lexer_token != token_kw_as)
- {
- lwb_error("Expecting AS, got %s\n", lexer_return_token(state));
- }
- lexer(state);
- vt = parse_type(state);
-
- se = symtab_find(state -> local_syms, vn);
- if (se)
- {
- lwb_error("Multiply defined local variable %s", vn);
- }
- state -> framesize += sizeof_type(vt);
- symtab_register(state -> local_syms, vn, -(state -> framesize), symtype_var, NULL);
-
- lw_free(vn);
- break;
-
- /* blank lines allowed */
- case token_eol:
- break;
-
- default:
- return;
- }
- if (state -> lexer_token != token_eol)
- lwb_error("Expecting end of line; got %s\n", lexer_return_token(state));
- lexer(state);
- }
-}
-
-static void parse_statements(cstate *state)
-{
- symtab_entry_t *se;
- int et;
-
- for (;;)
- {
- switch (state -> lexer_token)
- {
- /* blank lines allowed */
- case token_eol:
- break;
-
- /* variable assignment */
- case token_identifier:
- se = symtab_find(state -> local_syms, state -> lexer_token_string);
- if (!se)
- {
- se = symtab_find(state -> global_syms, state -> lexer_token_string);
- }
- if (!se)
- lwb_error("Unknown variable %s\n", state -> lexer_token_string);
- lexer(state);
- /* ensure the first token of the expression will be parsed correctly */
- state -> expression = 1;
- expect(state, token_op_assignment);
-
- /* parse the expression */
- et = parse_expression(state);
-
- /* check type compatibility */
-
- /* actually do the assignment */
-
- break;
-
- /* anything we don't recognize as a statement token breaks out */
- default:
- return;
- }
- if (state -> lexer_token != token_eol)
- lwb_error("Expecting end of line; got %s\n", lexer_return_token(state));
- lexer(state);
- }
-}
-
-
-/* issub means RETURNS is not allowed; !issub means RETURNS is required */
-
-static void parse_subfunc(cstate *state, int issub)
-{
- int pt, rt;
- char *subname, *pn;
- int vis = 0;
- symtab_entry_t *se;
- int paramsize = 0;
-
- state -> local_syms = symtab_init();
- state -> framesize = 0;
-
- lexer(state);
- if (state -> lexer_token != token_identifier)
- {
- lwb_error("Invalid sub name '%s'", state -> lexer_token_string);
- }
-
- subname = lw_strdup(state -> lexer_token_string);
-
- lexer(state);
- if (state -> lexer_token == token_kw_public || state -> lexer_token == token_kw_private)
- {
- if (state -> lexer_token == token_kw_public)
- vis = 1;
- lexer(state);
- }
-
- /* ignore the "PARAMS" keyword if present */
- if (state -> lexer_token == token_kw_params)
- lexer(state);
-
- if (state -> lexer_token == token_eol || state -> lexer_token == token_kw_returns)
- goto noparms;
-
-paramagain:
- if (state -> lexer_token != token_identifier)
- {
- lwb_error("Parameter name expected, got %s\n", lexer_return_token(state));
- }
- pn = lw_strdup(state -> lexer_token_string);
- lexer(state);
-
- if (state -> lexer_token != token_kw_as)
- lwb_error("Expecting AS\n");
- lexer(state);
-
- pt = parse_type(state);
-
- se = symtab_find(state -> local_syms, pn);
- if (se)
- {
- lwb_error("Duplicate parameter name %s\n", pn);
- }
- symtab_register(state -> local_syms, pn, paramsize, symtype_param, NULL);
- paramsize += sizeof_type(pt);
- lw_free(pn);
-
- if (state -> lexer_token == token_char && state -> lexer_token_string[0] == ',')
- {
- lexer(state);
- goto paramagain;
- }
-
-noparms:
- rt = -1;
- if (!issub)
- {
- if (state -> lexer_token != token_kw_returns)
- {
- lwb_error("FUNCTION must have RETURNS\n");
- }
- lexer(state);
-/* if (state -> lexer_token == token_identifier)
- {
- printf("Return value named: %s\n", state -> lexer_token_string);
-
- lexer(state);
- if (state -> lexer_token != token_kw_as)
- lwb_error("Execting AS after RETURNS");
- lexer(state);
- }
-*/
- rt = parse_type(state);
- }
- else
- {
- if (state -> lexer_token == token_kw_returns)
- {
- lwb_error("SUB cannot specify RETURNS\n");
- }
- }
-
-
- if (state -> lexer_token != token_eol)
- {
- lwb_error("EOL expected; found %s\n", lexer_return_token(state));
- }
-
-
- se = symtab_find(state -> global_syms, subname);
- if (se)
- {
- lwb_error("Multiply defined symbol %s\n", subname);
- }
-
- symtab_register(state -> global_syms, subname, -1, issub ? symtype_sub : symtype_func, NULL);
-
- state -> currentsub = subname;
- state -> returntype = rt;
- /* consume EOL */
- lexer(state);
-
- /* variable declarations */
- parse_decls(state);
-
- /* output function/sub prolog */
- emit_prolog(state, vis);
-
- /* parse statement block */
- parse_statements(state);
-
- if (issub)
- {
- if (state -> lexer_token != token_kw_endsub)
- {
- lwb_error("Expecting ENDSUB, got %s\n", lexer_return_token(state));
- }
- }
- else
- {
- if (state -> lexer_token != token_kw_endfunction)
- {
- lwb_error("Expecting ENDFUNCTION, got %s\n", lexer_return_token(state));
- }
- }
- /* output function/sub epilog */
- emit_epilog(state);
-
- lw_free(state -> currentsub);
- state -> currentsub = NULL;
- symtab_destroy(state -> local_syms);
- state -> local_syms = NULL;
-}
-
-void parser(cstate *state)
-{
- state -> lexer_curchar = -1;
- state -> global_syms = symtab_init();
-
- /* now look for a global declaration */
- for (;;)
- {
- state -> parser_state = parser_state_global;
- lexer(state);
- switch (state -> lexer_token)
- {
- case token_kw_function:
- printf("Function\n");
- parse_subfunc(state, 0);
- break;
-
- case token_kw_sub:
- printf("Sub\n");
- parse_subfunc(state, 1);
- break;
-
- /* blank lines are allowed */
- case token_eol:
- continue;
-
- /* EOF is allowed - end of parsing */
- case token_eof:
- return;
-
- default:
- lwb_error("Invalid token '%s' in global state\n", lexer_return_token(state));
- }
- }
-}
-
-static void parse_expr(cstate *state, int prec)
-{
- static const struct operinfo {
- int opernum;
- int operprec;
- } operators[] =
- {
- { token_op_plus, 100 },
- { token_op_minus, 100 },
- { token_op_times, 150 },
- { token_op_divide, 150 },
- { token_op_modulus, 150 },
- { token_op_and, 25 },
- { token_op_or, 20 },
- { token_op_xor, 20 },
- { token_op_band, 50 },
- { token_op_bor, 45 },
- { token_op_bxor, 45 },
- { -1, -1 }
- };
- int opern;
-
- parse_term(state);
-
-eval_next:
- for (opern = 0; operators[opern].opernum != -1; opern++)
- {
- if (operators[opern].opernum == state -> lexer_token)
- break;
- }
- if (operators[opern].opernum == -1)
- return;
-
- if (operators[opern].operprec <= prec)
- return;
-
- lexer(state);
-
- parse_expr(state, operators[opern].operprec);
-
- /* push operator */
-
- goto eval_next;
-}
-
-static void parse_term(cstate *state)
-{
-eval_next:
- /* parens */
- if (state -> lexer_token == token_op_oparen)
- {
- lexer(state);
- parse_expr(state, 0);
- expect(state, token_op_cparen);
- return;
- }
-
- /* unary plus; ignore it */
- if (state -> lexer_token == token_op_plus)
- {
- lexer(state);
- goto eval_next;
- }
-
- /* unary minus, precision 200 */
- if (state -> lexer_token == token_op_minus)
- {
- lexer(state);
- parse_expr(state, 200);
-
- /* push unary negation */
- }
-
- /* BNOT, NOT */
- if (state -> lexer_token == token_op_not || state -> lexer_token == token_op_bnot)
- {
- lexer(state);
- parse_expr(state, 200);
-
- /* push unary operator */
- }
-
- /* integer */
- if (state -> lexer_token == token_int)
- {
- }
-
- /* unsigned integer */
- if (state -> lexer_token == token_uint)
- {
- }
-
- /* variable or function call */
- if (state -> lexer_token == token_identifier)
- {
- lexer(state);
- if (state -> lexer_token == token_op_oparen)
- {
- /* function call */
- return;
- }
- /* variable */
- return;
- }
-
- lwb_error("Invalid input in expression; got %s\n", lexer_return_token(state));
-}
diff -r 6433cb024174 -r cca933d32298 lwbasic/rules.make
--- a/lwbasic/rules.make Thu Dec 22 18:03:04 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-dirname := $(dir $(lastword $(MAKEFILE_LIST)))
-lwbasic_dir := $(dirname)
-
-lwbasic_lsrcs := main.c input.c parser.c lexer.c emit.c symtab.c
-
-lwbasic_srcs := $(addprefix $(dirname),$(lwbasic_lsrcs))
-lwbasic_objs := $(lwbasic_srcs:.c=.o)
-lwbasic_deps := $(lwbasic_srcs:.c=.d)
-
-
-
-$(lwbasic_dir)lwbasic$(PROGSUFFIX): $(lwbasic_objs) lwlib $(lwbasic_dir)rules.make
- @echo "Linking $@"
- @$(CC) -o $@ $(lwbasic_objs) $(LDFLAGS)
-
-cleantargs := $(cleantargs) lwbasicclean
-realcleantargs := $(realcleantargs) lwbasicrealclean
-
-.PHONY: lwbasicclean lwbasicrealclean
-lwbasicrealclean:
- @echo "Really cleaning up lwbasic"
- @cd $(lwbasic_dir) && rm -f *.d
-
-lwbasicclean:
- @echo "Cleaning up lwbasic"
- @cd $(lwbasic_dir) && rm -f *.o *.exe lwbasic
-
--include $(lwbasic_deps)
diff -r 6433cb024174 -r cca933d32298 lwbasic/symtab.c
--- a/lwbasic/symtab.c Thu Dec 22 18:03:04 2011 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
-symtab.c
-
-Copyright © 2011 William Astle
-
-This file is part of LWTOOLS.
-
-LWTOOLS 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 3 of the License, or (at your option) any later
-version.
-
-This program 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, see .
-*/
-
-/*
-Symbol table handling
-*/
-
-#include
-#include
-
-#include
-#include
-
-#define __symtab_c_seen__
-#include "symtab.h"
-
-symtab_t *symtab_init(void)
-{
- symtab_t *st;
-
- st = lw_alloc(sizeof(symtab_t));
- st -> head = NULL;
- return st;
-}
-
-void symtab_destroy(symtab_t *st)
-{
- symtab_entry_t *se;
-
- while (st -> head)
- {
- se = st -> head;
- st -> head = se -> next;
- lw_free(se -> name);
- lw_free(se -> privdata);
- lw_free(se);
- }
- lw_free(st);
-}
-
-symtab_entry_t *symtab_find(symtab_t *st, char *name)
-{
- symtab_entry_t *se;
-
- for (se = st -> head; se; se = se -> next)
- {
- if (strcmp(se -> name, name) == 0)
- return se;
- }
- return NULL;
-}
-
-void symtab_register(symtab_t *st, char *name, int addr, int symtype, void *privdata)
-{
- symtab_entry_t *se;
-
- se = lw_alloc(sizeof(symtab_entry_t));
- se -> name = lw_strdup(name);
- se -> addr = addr;
- se -> symtype = symtype;
- se -> privdata = privdata;
- se -> next = st -> head;
- st -> head = se;
-}