@@ 0,0 1,170 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "lc3.h"
+#define MAXLINE 256
+#define MAXTOKEN 32
+#define MAXSYMBOL 128
+#define MAXARGS 3
+
+typedef struct Line Line;
+struct Line {
+ char label[MAXTOKEN];
+ u16int op;
+ u16int arg1;
+ u16int arg2;
+ u16int arg3;
+};
+
+typedef struct Symbol Symbol;
+struct Symbol {
+ char *label;
+ u16int addr;
+};
+
+Symbol symtab[MAXSYMBOL];
+
+int debug = 0;
+int symcount = 0;
+int lineno = 1;
+u16int orig, pc = 0x3000;
+char *asmfile;
+
+
+void
+usage(void)
+{
+ fprint(2, "lc3 -f FILE");
+}
+
+void
+*emalloc(ulong size)
+{
+ void *p;
+ p = malloc(size);
+ if(p != 0)
+ return p;
+ fprint(2, "Could not allocate memory!\n");
+ exits("Could not allocate memory!");
+ return p;
+}
+
+int
+gettoken(char **t, char *l)
+{
+ char *c;
+
+ for(c = l; *c != '\t' && *c != '\n'; c++){
+ if(c-l > MAXTOKEN){
+ fprint(2, "Token too long on line %d\n", lineno);
+ exits("Token too long");
+ }
+ }
+ vlong len = c - l;
+ *t = realloc(*t, sizeof(*t) * (len + 1));
+ **t = 0;
+ strncat(*t, l, len);
+ return len;
+}
+
+int
+parseline(char *l)
+{
+ int pos = 0;
+ int c = 0;
+ char *t = nil;
+ while(l[0] && pos < MAXARGS){
+ if(l[0] == ';' || l[0] == '\n') return 0;
+ if(l[0] == ' ' || l[0] == '\t') {
+ l++;
+ pos++;
+ } else if(pos == 0 && l[0] != '\t'){
+ // It's a label
+ symtab[symcount].addr = pc;
+ l += gettoken(&t, l);
+ symtab[symcount].label = t;
+ symcount++;
+ pos++;
+ } else if(pos == 1){
+ // It's an instruction or directive
+ c = gettoken(&t, l);
+ if(c == 0) return 0;
+ l += c;
+ print("TOKEN: %s\n", t);
+ if(strcmp(t,".END") == 0) {
+ return -1;
+ } else if(strcmp(t,".ORIG") == 0){
+ //FIXME: only supporting hex for now
+ l+=2; //skipping hex number indicator to raw number
+ gettoken(&t, l);
+ // re-use c
+ c = (int) strtol(t, 0, 16);
+ pc = origin = c;
+ if(pc != c) { // not a valid u16int
+ fprint(2, ".ORIG argument too large\n");
+ exits("Orig too big");
+ }
+ if(debug)
+ print("updated origin to %x\n", origin);
+ return 0;
+ } else if(strcmp(t,"NOP") == 0) {
+ pc++;
+ pos++;
+ return 1;
+ } else {
+ fprint(
+ 2,
+ "%s:%d Invalid instruction or directive: %s\n",
+ asmfile,
+ lineno,
+ t
+ );
+ exits("Syntax error");
+ }
+ } else if(pos==2){
+ return 1;
+ }
+ }
+ fprint(2, "Should not get here\n");
+ return -1;
+}
+
+void
+parse(FILE *fh)
+{
+ char l[MAXLINE] = {0};
+ while(fgets(l, MAXLINE, fh) != nil){
+ if(parseline(l) < 0) break;
+ lineno++;
+ }
+}
+
+void
+main(int argc, char* argv[])
+{
+ FILE *in, *out;
+
+ ARGBEGIN {
+ case 'd':
+ debug++;
+ break;
+ case 'f':
+ asmfile = EARGF(usage());
+ } ARGEND;
+
+ in = fopen(asmfile, "r");
+ parse(in);
+ if(debug){
+ print("Symbol table:\n");
+ print("No.\tLabel\tAddr\n");
+ for(int i = 0; i < symcount; i++){
+ print(
+ "%d\t%s\t\%04x\n",
+ i,
+ symtab[i].label,
+ symtab[i].addr
+ );
+ }
+ }
+ exits(nil);
+}