summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--Makefile27
-rwxr-xr-xe4
-rw-r--r--e.l57
-rw-r--r--e.y117
-rwxr-xr-xexamples/factorialbin0 -> 15688 bytes
-rw-r--r--examples/factorial.e16
-rw-r--r--lib.c7
-rw-r--r--qbe.c122
-rw-r--r--qbe.h6
-rw-r--r--types.h18
11 files changed, 378 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d48ea8e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.o
+eqbe
+y.*
+lex.*
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ea84791
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,27 @@
+e: lex.yy.c y.tab.c qbe.o
+ cc lex.yy.c y.tab.c qbe.o -o eqbe
+
+lib.o: lib.c
+ cc lib.c -c -o lib.o
+
+qbe.o: qbe.c
+ cc qbe.c -c -o qbe.o
+
+lex.yy.c: y.tab.c e.l
+ lex e.l
+
+y.tab.c: e.y
+ yacc -d e.y
+
+clean:
+ rm -rf lex.yy.c y.tab.c y.tab.h eqbe *.o
+
+install: e lib.o
+ chmod +x ./e
+ cp e eqbe /usr/local/bin
+ cp lib.o /usr/local/share/
+
+uninstall:
+ rm -rf /usr/local/bin/{e,eqbe}
+ rm -rf /usr/local/share/lib.o
+
diff --git a/e b/e
new file mode 100755
index 0000000..f431109
--- /dev/null
+++ b/e
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+eqbe < $1 | qbe > /tmp/tmp.s
+cc /usr/local/share/lib.o /tmp/tmp.s -o $2
diff --git a/e.l b/e.l
new file mode 100644
index 0000000..fe43408
--- /dev/null
+++ b/e.l
@@ -0,0 +1,57 @@
+%{
+#include "types.h"
+#include "y.tab.h"
+#include <stdlib.h>
+%}
+
+%option noyywrap
+%option yylineno
+
+%%
+[0-9]+ {
+ yylval.intlit = atoi(yytext);
+ return INTLIT;
+}
+
+[A-Z] {
+ yylval.funcname = yytext[0];
+ return FUNCTIONNAME;
+}
+
+
+[a-z] {
+ yylval.varname = yytext[0];
+ return VARNAME;
+}
+
+[-=+*/{}:] {
+ return yytext[0];
+}
+
+dec {
+ return FUNCTIONDEC;
+}
+
+print {
+ return PRINT;
+}
+
+input {
+ return INPUT;
+}
+
+ret {
+ return RET;
+}
+
+jmp {
+ return JMP;
+}
+
+jnz {
+ return JNZ;
+}
+
+
+[:\n\t\v ] {;}
+%%
diff --git a/e.y b/e.y
new file mode 100644
index 0000000..0951b64
--- /dev/null
+++ b/e.y
@@ -0,0 +1,117 @@
+%{
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "types.h"
+#include "qbe.h"
+
+extern int yylex();
+extern int yylineno;
+extern char *yytext;
+void yyerror(const char* s);
+
+exp *exprs[1024];
+int exprcount = 0;
+
+
+function *funcs[1024];
+int funccount = 0;
+
+exp *newexpr(char name, char op, int val, bool isvar) {
+ exp *e = malloc(sizeof(exp));
+
+ e->name = name;
+ e->op = op;
+ e->var = isvar;
+ e->v = val;
+}
+
+void appendexpr(exp *e) {
+ exprs[exprcount] = e;
+ exprcount++;
+}
+
+void appendfunction(function *f) {
+ funcs[funccount] = f;
+ funccount++;
+}
+
+function *copyexprsandclear(char name) {
+ function *f = malloc(sizeof(function));
+ f->name = name;
+ memcpy(f->exprs, exprs, sizeof(exp) * 1024);
+ f->exprcount = exprcount;
+
+ exprcount = 0;
+}
+
+%}
+
+
+%union {
+ char funcname;
+ char varname;
+ int intlit;
+ exp *expr;
+}
+
+%token <intlit> INTLIT
+%token <funcname> FUNCTIONNAME
+%token <varname> VARNAME
+%token FUNCTIONDEC
+%token PRINT
+%token INPUT
+%token RET
+%token JMP
+%token JNZ
+
+%type <expr> EXPR
+
+%%
+PROG : PROG F
+ | F
+ ;
+
+F : FUNCTIONDEC FUNCTIONNAME '{' EXPRS '}' {appendfunction(copyexprsandclear($2));}
+ ;
+
+EXPRS : EXPRS EXPR {appendexpr($2);}
+ | EXPR {appendexpr($1);}
+ ;
+
+EXPR : VARNAME {$$ = newexpr($1, 0, 0, false);}
+ | VARNAME '=' INTLIT {$$ = newexpr($1, '=', $3, false);}
+ | VARNAME '+' INTLIT {$$ = newexpr($1, '+', $3, false);}
+ | VARNAME '-' INTLIT {$$ = newexpr($1, '-', $3, false);}
+ | VARNAME '*' INTLIT {$$ = newexpr($1, '*', $3, false);}
+ | VARNAME '/' INTLIT {$$ = newexpr($1, '/', $3, false);}
+
+ | VARNAME '=' VARNAME {$$ = newexpr($1, '=', $3, true);}
+ | VARNAME '+' VARNAME {$$ = newexpr($1, '+', $3, true);}
+ | VARNAME '-' VARNAME {$$ = newexpr($1, '-', $3, true);}
+ | VARNAME '*' VARNAME {$$ = newexpr($1, '*', $3, true);}
+ | VARNAME '/' VARNAME {$$ = newexpr($1, '/', $3, true);}
+
+
+ | PRINT VARNAME {$$ = newexpr($2, 'p', 0, false);}
+ | VARNAME '=' INPUT {$$ = newexpr($1, 'i', 0, false);}
+ | VARNAME '=' FUNCTIONNAME {$$ = newexpr($1, 'c', $3, false);}
+ | RET VARNAME {$$ = newexpr($2, 'r', 0, false);}
+
+ | VARNAME ':' {$$ = newexpr($1, 'l', 0, false);}
+ | JMP VARNAME ':' {$$ = newexpr($2, 'j', 0, false);}
+ | JNZ VARNAME VARNAME ':' {$$ = newexpr($3, 'z', $2, false);}
+ ;
+%%
+void yyerror(const char *msg) {
+ fprintf(stderr, "%d:%s\n%s\n", yylineno, msg, yytext);
+}
+
+int main() {
+ yyparse();
+
+ compile(stdout, funcs, funccount);
+
+ return 0;
+}
diff --git a/examples/factorial b/examples/factorial
new file mode 100755
index 0000000..c51b931
--- /dev/null
+++ b/examples/factorial
Binary files differ
diff --git a/examples/factorial.e b/examples/factorial.e
new file mode 100644
index 0000000..7cdd3ed
--- /dev/null
+++ b/examples/factorial.e
@@ -0,0 +1,16 @@
+dec F {
+ a = input
+ t = 1
+l:
+ t * a
+ a - 1
+ jnz a l:
+ ret t
+}
+
+dec M {
+l:
+ a = F
+ print a
+ jmp l:
+}
diff --git a/lib.c b/lib.c
new file mode 100644
index 0000000..aa14a03
--- /dev/null
+++ b/lib.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int readint() {
+ int i = 0;
+ scanf("%d", &i);
+ return i;
+}
diff --git a/qbe.c b/qbe.c
new file mode 100644
index 0000000..ed3daf9
--- /dev/null
+++ b/qbe.c
@@ -0,0 +1,122 @@
+#include <stdio.h>
+#include "types.h"
+
+int endcount = 0;
+
+void compileexpr(FILE *f, exp *e) {
+ switch (e->op) {
+ case '+':
+ if (e->var)
+ fprintf(f,
+ "%%%c =w add %%%c, %%%c\n",
+ e->name, e->name, e->vv);
+ else
+ fprintf(f,
+ "%%%c =w add %%%c, %d\n",
+ e->name, e->name, e->v);
+ break;
+ case '-':
+ if (e->var)
+ fprintf(f,
+ "%%%c =w sub %%%c, %%%c\n",
+ e->name, e->name, e->vv);
+ else
+ fprintf(f,
+ "%%%c =w sub %%%c, %d\n",
+ e->name, e->name, e->v);
+ break;
+ case '*':
+ if (e->var)
+ fprintf(f,
+ "%%%c =w mul %%%c, %%%c\n",
+ e->name, e->name, e->vv);
+ else
+ fprintf(f,
+ "%%%c =w mul %%%c, %d\n",
+ e->name, e->name, e->v);
+ break;
+ case '/':
+ if (e->var)
+ fprintf(f,
+ "%%%c =w div %%%c, %%%c\n",
+ e->name, e->name, e->vv);
+ else
+ fprintf(f,
+ "%%%c =w div %%%c, %d\n",
+ e->name, e->name, e->v);
+ break;
+
+ case 0:
+ fprintf(f,
+ "%%%c =w copy 0\n",
+ e->name);
+ break;
+
+ case '=':
+ fprintf(f,
+ "%%%c =w copy %d\n",
+ e->name, e->v);
+ break;
+
+ case 'p':
+ fprintf(f,
+ "call $printf(l $fmt, ..., w %%%c)\n",
+ e->name);
+ break;
+
+ case 'i':
+ fprintf(f,
+ "%%%c =w call $readint()\n",
+ e->name);
+ break;
+
+ case 'r':
+ fprintf(f,
+ "ret %%%c\n",
+ e->name);
+ break;
+ case 'l':
+ fprintf(f,
+ "@label%c\n",
+ e->name);
+ break;
+ case 'j':
+ fprintf(f,
+ "jmp @label%c\n",
+ e->name);
+ break;
+ case 'z':
+ fprintf(f,
+ "jnz %%%c, @label%c, @end%d\n@end%d\n",
+ e->vv, e->name, endcount, endcount);
+ endcount++;
+ break;
+ default:
+ fprintf(f,
+ "%%%c =w call $%c()\n",
+ e->name, e->vv);
+ break;
+
+ }
+}
+
+void compilefunc(FILE *file, function *f) {
+ if (f->name == 'M')
+ fprintf(file, "export function w $main() {\n@start\n");
+ else
+ fprintf(file, "export function w $%c() {\n@start\n", f->name);
+
+ for (int i = 0; i < f->exprcount; i++) {
+ compileexpr(file, f->exprs[i]);
+ }
+
+ fprintf(file, "}\n");
+}
+
+void compile(FILE *file, function *f[], int count) {
+ for (int i = 0; i < count; i++) {
+ compilefunc(file, f[i]);
+ }
+ printf("data $fmt = { b \"%%d\\n\", b 0 }\n");
+ printf("data $fmtin = { b \"%%d\", b 0 }\n");
+}
diff --git a/qbe.h b/qbe.h
new file mode 100644
index 0000000..28f71bc
--- /dev/null
+++ b/qbe.h
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void compileexpr(FILE *f, exp *e);
+void compilefunc(FILE *file, function *f);
+void compile(FILE *file, function *f[], int count);
+
diff --git a/types.h b/types.h
new file mode 100644
index 0000000..b2e50c2
--- /dev/null
+++ b/types.h
@@ -0,0 +1,18 @@
+#include <stdbool.h>
+
+typedef struct exp {
+ char name;
+ char op;
+
+ bool var;
+ union {
+ int v;
+ char vv;
+ };
+} exp;
+
+typedef struct function {
+ exp *exprs[1024];
+ int exprcount;
+ char name;
+} function;