summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--s3/builtin.c46
-rw-r--r--s3/dat.h23
-rw-r--r--s3/fns.h7
-rw-r--r--s3/mkfile16
-rw-r--r--s3/rhoc.y172
-rw-r--r--s3/sym.c31
6 files changed, 295 insertions, 0 deletions
diff --git a/s3/builtin.c b/s3/builtin.c
new file mode 100644
index 0000000..e9208cf
--- /dev/null
+++ b/s3/builtin.c
@@ -0,0 +1,46 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+#include "y.tab.h"
+
+static Const consts[] = {
+ "π", 3.14159265358979323846,
+ "e", 2.71828182845904523536,
+ "γ", 0.57721566490153286060,
+ "DEG", 57.29577951308232087680,
+ "Φ", 1.61803398874989484820,
+};
+
+static Builtin builtins[] = {
+ "sin", sin,
+ "cos", cos,
+ "atan", atan,
+ "atan2", atan2,
+ "log", log,
+ "log10", log10,
+ "exp", exp,
+ "sqrt", sqrt,
+ "int", round,
+ "abs", fabs,
+};
+
+double
+round(double n)
+{
+ return floor(n + 0.5);
+}
+
+void
+init(void)
+{
+ Symbol *s;
+ int i;
+
+ for(i = 0; i < nelem(consts); i++)
+ install(consts[i].name, CONST, consts[i].val);
+ for(i = 0; i < nelem(builtins); i++){
+ s = install(builtins[i].name, BLTIN, 0);
+ s->u.fn = builtins[i].fn;
+ }
+}
diff --git a/s3/dat.h b/s3/dat.h
new file mode 100644
index 0000000..9cdb6c7
--- /dev/null
+++ b/s3/dat.h
@@ -0,0 +1,23 @@
+typedef struct Symbol Symbol;
+typedef struct Const Const;
+typedef struct Builtin Builtin;
+
+struct Symbol {
+ char *name;
+ int type;
+ union {
+ double val;
+ double (*fn)(double);
+ } u;
+ Symbol *next;
+};
+
+struct Const {
+ char *name;
+ double val;
+};
+
+struct Builtin {
+ char *name;
+ double (*fn)();
+};
diff --git a/s3/fns.h b/s3/fns.h
new file mode 100644
index 0000000..3591979
--- /dev/null
+++ b/s3/fns.h
@@ -0,0 +1,7 @@
+int yyparse(void);
+
+Symbol *install(char *, int, double);
+Symbol *lookup(char *);
+double round(double);
+void init(void);
+void *emalloc(ulong);
diff --git a/s3/mkfile b/s3/mkfile
new file mode 100644
index 0000000..70aeac7
--- /dev/null
+++ b/s3/mkfile
@@ -0,0 +1,16 @@
+</$objtype/mkfile
+
+TARG=rhoc3
+OFILES=\
+ y.tab.$O\
+ sym.$O\
+ builtin.$O
+YFILES=\
+ rhoc.y
+HFILES=\
+ dat.h\
+ fns.h\
+ y.tab.h
+BIN=/$objtype/bin
+
+</sys/src/cmd/mkone
diff --git a/s3/rhoc.y b/s3/rhoc.y
new file mode 100644
index 0000000..ea62b13
--- /dev/null
+++ b/s3/rhoc.y
@@ -0,0 +1,172 @@
+%{
+#include "dat.h"
+%}
+%union {
+ double val;
+ Symbol *sym;
+}
+%token <val> NUMBER
+%token <sym> VAR CONST BLTIN UNDEF
+%type <val> expr asgn
+%right '='
+%left '+' '-'
+%left '*' '/'
+%left '%'
+%right '^'
+%left UMINUS
+%%
+list: /* ε */
+ | list '\n'
+ | list asgn '\n'
+ | list expr '\n' { print("\t%.8g\n", $2); }
+ | list error '\n' { yyerrok; }
+ ;
+asgn: VAR '=' expr
+ {
+ if($1->type == CONST)
+ rterror("assignment to constant");
+ $$ = $1->u.val = $3;
+ $1->type = VAR;
+ }
+ ;
+expr: NUMBER
+ | VAR
+ {
+ if($1->type == UNDEF)
+ rterror("undefined variable");
+ $$ = $1->u.val;
+ }
+ | asgn
+ | BLTIN '(' expr ')' { $$ = $1->u.fn($3); }
+ | '-' expr %prec UMINUS { $$ = -$2; }
+ | expr '+' expr { $$ = $1 + $3; }
+ | expr '-' expr { $$ = $1 - $3; }
+ | expr '*' expr { $$ = $1 * $3; }
+ | expr '/' expr
+ {
+ if($3 == 0)
+ rterror("division by zero");
+ $$ = $1 / $3;
+ }
+ | expr '%' expr { $$ = fmod($1, $3); }
+ | expr '^' expr { $$ = pow($1, $3); }
+ | expr '(' expr ')' { $$ = $1 * $3; }
+ | '(' expr ')' { $$ = $2; }
+ ;
+%%
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+#include "fns.h"
+
+Biobuf *bin;
+jmp_buf begin;
+int lineno;
+int prompt;
+
+void *
+emalloc(ulong n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil)
+ sysfatal("malloc: %r");
+ memset(p, 0, n);
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
+
+void
+yyerror(char *msg)
+{
+ fprint(2, "%s at line %d\n", msg, lineno);
+}
+
+void
+rterror(char *msg)
+{
+ fprint(2, "%s at line %d\n", msg, lineno-1);
+ longjmp(begin, 0);
+}
+
+int
+catch(void *ureg, char *msg)
+{
+ if(strncmp(msg, "sys: fp", 7) == 0){
+ yyerror("floating point exception");
+ notejmp(ureg, begin, 0);
+ }
+ return 0;
+}
+
+int
+yylex(void)
+{
+ Symbol *s;
+ char sname[256], *p;
+ Rune r;
+
+ if(prompt){
+ print("%d: ", lineno);
+ prompt--;
+ }
+ while((r = Bgetrune(bin)) == ' ' || r == '\t')
+ ;
+ if(r == Beof)
+ return 0;
+ if(r == '.' || isdigitrune(r)){
+ Bungetrune(bin);
+ Bgetd(bin, &yylval.val);
+ return NUMBER;
+ }
+ if(isalpharune(r)){
+ p = sname;
+ do{
+ if(p+runelen(r) - sname >= sizeof(sname))
+ return r; /* force syntax error. */
+ p += runetochar(p, &r);
+ }while((r = Bgetrune(bin)) != Beof &&
+ (isalpharune(r) || isdigitrune(r)));
+ Bungetrune(bin);
+ *p = 0;
+ if((s = lookup(sname)) == nil)
+ s = install(sname, UNDEF, 0);
+ yylval.sym = s;
+ return s->type == UNDEF || s->type == CONST ? VAR : s->type;
+ }
+ if(r == '\n'){
+ lineno++;
+ prompt++;
+ }
+ return r;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ ARGBEGIN{
+ default: usage();
+ }ARGEND;
+ if(argc > 0)
+ usage();
+ atnotify(catch, 1);
+ bin = Bfdopen(0, OREAD);
+ if(bin == nil)
+ sysfatal("Bfdopen: %r");
+ lineno++;
+ prompt++;
+ init();
+ setjmp(begin);
+ yyparse();
+ Bterm(bin);
+ exits(0);
+}
diff --git a/s3/sym.c b/s3/sym.c
new file mode 100644
index 0000000..8749791
--- /dev/null
+++ b/s3/sym.c
@@ -0,0 +1,31 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+static Symbol *symtab;
+
+Symbol *
+install(char *s, int t, double v)
+{
+ Symbol *sym;
+
+ sym = emalloc(sizeof(Symbol));
+ sym->name = strdup(s);
+ sym->type = t;
+ sym->u.val = v;
+ sym->next = symtab;
+ symtab = sym;
+ return sym;
+}
+
+Symbol *
+lookup(char *s)
+{
+ Symbol *sym;
+
+ for(sym = symtab; sym != nil; sym = sym->next)
+ if(strcmp(sym->name, s) == 0)
+ return sym;
+ return nil;
+}