aboutsummaryrefslogtreecommitdiff
path: root/works/life
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-12-02 21:59:36 +0800
committercrupest <crupest@outlook.com>2021-12-02 21:59:36 +0800
commit27556004e8e12a72ed1c2c70212f6b660ed798c3 (patch)
tree9191fca88d48c97fce6e777037c93c57c29edad2 /works/life
parente3fb643403ae71a38cba404e8d548d7a49cfdb88 (diff)
downloadcrupest-27556004e8e12a72ed1c2c70212f6b660ed798c3.tar.gz
crupest-27556004e8e12a72ed1c2c70212f6b660ed798c3.tar.bz2
crupest-27556004e8e12a72ed1c2c70212f6b660ed798c3.zip
import(life): ...
Diffstat (limited to 'works/life')
-rw-r--r--works/life/compile-principle-experiment/4/lex.l20
-rw-r--r--works/life/compile-principle-experiment/4/main.c279
-rw-r--r--works/life/compile-principle-experiment/4/main.h41
-rw-r--r--works/life/compile-principle-experiment/4/makefile22
-rw-r--r--works/life/compile-principle-experiment/4/syn.y39
5 files changed, 401 insertions, 0 deletions
diff --git a/works/life/compile-principle-experiment/4/lex.l b/works/life/compile-principle-experiment/4/lex.l
new file mode 100644
index 0000000..e7731ca
--- /dev/null
+++ b/works/life/compile-principle-experiment/4/lex.l
@@ -0,0 +1,20 @@
+%{
+#include "main.h"
+#include "syn.h"
+%}
+%option noyywrap
+%%
+[ \t] { ; } /* skip blanks and tabs */
+[0-9]+\.?|[0-9]*\.[0-9]+ {
+ Symbol *s = cru_symbol_install("", UNDEF, (SymbolValue)0.0);
+ sscanf(yytext, "%lf", &s->value.val);
+ yylval.sym = s;
+ return NUMBER; }
+[a-zA-Z][a-zA-Z0-9]* {
+ Symbol *s;
+ if ((s=cru_symbol_lookup(yytext)) == 0)
+ s = cru_symbol_install(yytext, UNDEF, (SymbolValue)0.0);
+ yylval.sym = s;
+ return s->type == UNDEF ? VAR : s->type; }
+\n { lineno++; return '\n'; } /* everything else */
+. { return yytext[0]; }
diff --git a/works/life/compile-principle-experiment/4/main.c b/works/life/compile-principle-experiment/4/main.c
new file mode 100644
index 0000000..258ccc7
--- /dev/null
+++ b/works/life/compile-principle-experiment/4/main.c
@@ -0,0 +1,279 @@
+#include "main.h"
+
+#include "syn.h"
+
+#include <errno.h>
+#include <math.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static Symbol *symlist = 0; /* symbol table: linked list */
+
+void *emalloc(size_t n) /* check return from malloc */
+{
+ void *p = malloc(n);
+ if (p == 0)
+ execerror("out of memory", (char *)0);
+ return p;
+}
+
+Symbol *cru_symbol_lookup(const char *name) {
+ for (Symbol *sp = symlist; sp != NULL; sp = sp->next)
+ if (strcmp(sp->name, name) == 0)
+ return sp;
+ return NULL;
+}
+
+Symbol *cru_symbol_install(const char *name, int type, SymbolValue value) {
+ Symbol *sp = (Symbol *)emalloc(sizeof(Symbol));
+ sp->name = emalloc(strlen(name) + 1);
+ strcpy(sp->name, name);
+ sp->type = type;
+ sp->value = value;
+ sp->next = symlist;
+ symlist = sp;
+ return sp;
+}
+
+jmp_buf begin;
+int lineno;
+
+void warning(const char *s, const char *t) {
+ fprintf(stderr, "%s", s);
+ if (t)
+ fprintf(stderr, " %s", t);
+ fprintf(stderr, " near line %d\n", lineno);
+}
+
+void yyerror(const char *s) { warning(s, NULL); }
+
+void execerror(const char *s, const char *t) {
+ warning(s, t);
+ longjmp(begin, 0);
+}
+
+double errcheck(double result, const char *name) {
+ if (errno == EDOM) {
+ errno = 0;
+ execerror(name, "argument out of domain");
+ } else if (errno == ERANGE) {
+ errno = 0;
+ execerror(name, "result out of range");
+ }
+ return result;
+}
+
+double Log(double x) { return errcheck(log(x), "log"); }
+double Log10(double x) { return errcheck(log10(x), "log10"); }
+double Sqrt(double x) { return errcheck(sqrt(x), "sqrt"); }
+double Exp(double x) { return errcheck(exp(x), "exp"); }
+double Pow(double x, double y) { return errcheck(pow(x, y), "exponentiation"); }
+double integer(double x) { return (double)(long)x; }
+
+static struct { /* Constants */
+ char *name;
+ double cval;
+} consts[] = {
+ {"PI", 3.14159265358979323846}, {"E", 2.71828182845904523536},
+ {"GAMMA", 0.57721566490153286060}, {"DEG", 57.29577951308232087680},
+ {"PHI", 1.61803398874989484820},
+};
+
+static struct { /* Built-ins */
+ char *name;
+ double (*func)();
+} builtins[] = {
+ {"sin", sin}, {"cos", cos}, {"atan", atan},
+ {"log", Log}, {"log10", Log10}, {"exp", Exp},
+ {"sqrt", Sqrt}, {"int", integer}, {"abs", fabs},
+};
+
+int initcode();
+int execute(Inst *p);
+
+void init() {
+ initcode();
+ for (int i = 0; i < sizeof(consts) / sizeof(*consts); i++)
+ cru_symbol_install(consts[i].name, VAR, (SymbolValue)consts[i].cval);
+ for (int i = 0; i < sizeof(builtins) / sizeof(*builtins); i++) {
+ cru_symbol_install(builtins[i].name, BLTIN, (SymbolValue)builtins->func);
+ }
+}
+
+int main(int argc, char **argv) {
+ init();
+ (void)setjmp(begin);
+ yyparse();
+ execute(prog);
+
+ return 0;
+}
+
+#define NSTACK 256
+static Datum stack[NSTACK]; /* the stack */
+static Datum *stackp; /* next free spot on stack */
+
+#define NPROG 2000
+Inst prog[NPROG]; /* the machine */
+Inst *progp; /* next free spot for code generation */
+Inst *pc; /* program counter during execution */
+
+int initcode() /* initialize for code generation */
+{
+ stackp = stack;
+ progp = prog;
+ return 0;
+}
+
+int push(Datum d) /* push d onto stack */
+{
+ if (stackp >= &stack[NSTACK])
+ execerror("stack overflow", (char *)0);
+ *stackp++ = d;
+ return 0;
+}
+
+Datum pop() /* pop and return top elem from stack */
+{
+ if (stackp <= stack)
+ execerror("stack underflow", (char *)0);
+ return *--stackp;
+}
+
+int constpush() /* push constant onto stack */
+{
+ Datum d;
+ d.val = ((Symbol *)*pc++)->value.val;
+ push(d);
+ return 0;
+}
+
+int varpush() /* push variable onto stack */
+{
+ Datum d;
+ d.sym = (Symbol *)(*pc++);
+ push(d);
+ return 0;
+}
+
+int bltin() /* evaluate built-in on top of stack */
+{
+ Datum d;
+ d = pop();
+ d.val = (*(double (*)())(*pc++))(d.val);
+ push(d);
+ return 0;
+}
+
+int eval() /* evaluate variable on stack */
+{
+ Datum d;
+ d = pop();
+ if (d.sym->type == UNDEF)
+ execerror("undefined variable", d.sym->name);
+ d.val = d.sym->value.val;
+ push(d);
+ return 0;
+}
+
+int add() /* add top two elems on stack */
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val += d2.val;
+ push(d1);
+ return 0;
+}
+
+int sub() /* subtract top of stack from next */
+{
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val -= d2.val;
+ push(d1);
+ return 0;
+}
+
+int mul() {
+ Datum d1, d2;
+ d2 = pop();
+ d1 = pop();
+ d1.val *= d2.val;
+ push(d1);
+ return 0;
+}
+
+int mydiv() {
+ Datum d1, d2;
+ d2 = pop();
+ if (d2.val == 0.0)
+ execerror("division by zero", (char *)0);
+ d1 = pop();
+ d1.val /= d2.val;
+ push(d1);
+ return 0;
+}
+
+int negate() {
+ Datum d;
+ d = pop();
+ d.val = -d.val;
+ push(d);
+ return 0;
+}
+
+int power() {
+ Datum d1, d2;
+ extern double Pow();
+ d2 = pop();
+ d1 = pop();
+ d1.val = Pow(d1.val, d2.val);
+ push(d1);
+ return 0;
+}
+
+int assign() /* assign top value to next value */
+{
+ Datum d1, d2;
+ d1 = pop();
+ d2 = pop();
+ if (d1.sym->type != VAR && d1.sym->type != UNDEF)
+ execerror("assignment to non-variable", d1.sym->name);
+ d1.sym->value.val = d2.val;
+ d1.sym->type = VAR;
+ push(d2);
+ return 0;
+}
+
+int print() /* pop top value from stack, print it */
+{
+ Datum d;
+ d = pop();
+ printf("\t%.8g\n", d.val);
+ return 0;
+}
+
+Inst *code(Inst f) /* install one instruction or operand */
+{
+ Inst *oprogp = progp;
+ if (progp >= &prog[NPROG])
+ execerror("program too big", (char *)0);
+ *progp++ = f;
+ return oprogp;
+}
+
+int execute(Inst *p) /* run the machine */
+{
+ for (pc = p; *pc != STOP;)
+ (*(*pc++))();
+ return 0;
+}
+
+int mypop() {
+ pop();
+ return 0;
+}
diff --git a/works/life/compile-principle-experiment/4/main.h b/works/life/compile-principle-experiment/4/main.h
new file mode 100644
index 0000000..96bd9e7
--- /dev/null
+++ b/works/life/compile-principle-experiment/4/main.h
@@ -0,0 +1,41 @@
+#pragma once
+
+typedef union SymbolValue {
+ double val;
+ double (*ptr)();
+} SymbolValue;
+
+typedef struct Symbol {
+ char *name;
+ int type;
+ SymbolValue value;
+ struct Symbol *next;
+} Symbol;
+
+Symbol *cru_symbol_lookup(const char *name);
+Symbol *cru_symbol_install(const char *name, int type, SymbolValue value);
+
+double Pow(double x, double y);
+
+int yylex();
+int yyparse();
+void yyerror(const char *s);
+
+extern int lineno;
+void execerror(const char *s, const char *t);
+
+typedef union Datum { /* interpreter stack type */
+ double val;
+ Symbol *sym;
+} Datum;
+extern Datum pop();
+int mypop();
+
+typedef int (*Inst)(); /* machine instruction */
+#define STOP (Inst)0
+
+extern Inst prog[];
+extern int eval(), add(), sub(), mul(), mydiv(), negate(), power();
+extern int assign(), bltin(), varpush(), constpush(), print();
+
+extern Inst *code(Inst f);
diff --git a/works/life/compile-principle-experiment/4/makefile b/works/life/compile-principle-experiment/4/makefile
new file mode 100644
index 0000000..756cdcb
--- /dev/null
+++ b/works/life/compile-principle-experiment/4/makefile
@@ -0,0 +1,22 @@
+main: main.o lex.o syn.o
+ cc -g lex.o syn.o main.o -o main
+
+main.o: main.c main.h syn.h
+ cc -g -c -o main.o main.c
+
+lex.c: lex.l
+ flex -o lex.c lex.l
+
+lex.o: lex.c syn.h main.h
+ cc -g -c -o lex.o lex.c
+
+syn.c syn.h: syn.y
+ bison syn.y -d -o syn.c
+
+syn.o: syn.c syn.h main.h
+ cc -g -c -o syn.o syn.c
+
+PHONY: clean
+
+clean:
+ rm -f *.o lex.c syn.c syn.h main
diff --git a/works/life/compile-principle-experiment/4/syn.y b/works/life/compile-principle-experiment/4/syn.y
new file mode 100644
index 0000000..ebe113f
--- /dev/null
+++ b/works/life/compile-principle-experiment/4/syn.y
@@ -0,0 +1,39 @@
+%{
+#include "main.h"
+#include <stdio.h>
+#define code2(c1,c2) code(c1); code(c2)
+#define code3(c1,c2,c3) code(c1); code(c2); code(c3)
+%}
+%union {
+ Symbol *sym; /* symbol table pointer */
+ double val;
+ Inst *inst; /* machine instruction */
+}
+%token <sym> NUMBER VAR BLTIN UNDEF
+%right '='
+%left '+' '-'
+%left '*' '/'
+%left UNARYMINUS
+%right '^' /* exponentiation */
+%%
+list: /* nothing */
+ | list '\n'
+ | list asgn '\n' { code2(mypop, STOP); return 1; }
+ | list expr '\n' { code2(print, STOP); return 1; }
+ | list error '\n' { yyerrok; }
+ ;
+asgn: VAR '=' expr { code3(varpush,(Inst)$1,assign); }
+ ;
+expr: NUMBER { code2(constpush, (Inst)$1); }
+ | VAR { code3(varpush, (Inst)$1, eval); }
+ | asgn
+ | BLTIN '(' expr ')' { code2(bltin, (Inst)$1->value.ptr); }
+ | '(' expr ')'
+ | expr '+' expr { code(add); }
+ | expr '-' expr { code(sub); }
+ | expr '*' expr { code(mul); }
+ | expr '/' expr { code(mydiv); }
+ | expr '^' expr { code(power); }
+ | '-' expr %prec UNARYMINUS { code(negate); }
+ ;
+%%