ref: dd9a8551019ff0bfb4c5af583dc60419d28c4bb1
author: Jacob Moody <moody@posixcafe.org>
date: Thu Nov 16 23:15:12 EST 2023
initial commit, rough idea
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,11 @@
+</$objtype/mkfile
+
+BIN=$home/bin/$objtype
+TARG=nl
+OFILES=\
+ y.tab.$O\
+
+YFILES=\
+ n.y\
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/n.y
@@ -1,0 +1,238 @@
+%{
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+
+int goteof;
+int lineno;
+int yyparse(void);
+void yyerror(char*);
+
+%}
+
+%union
+{
+ char *sval;
+ long ival;
+}
+
+%token FUNC DEF IF FOR STRUCT MOD USE TYPE NAME NUM OR AND NOTEQ SHIFTL SHIFTR
+
+%token <sval> NAME TYPE;
+%token <ival> NUM
+
+%%
+
+prog
+: prog top
+| top
+
+sem
+: ';'
+
+top
+: FUNC NAME '(' args ')' '-' '>' return '{' stmts '}'
+| MOD NAME sem
+| USE NAME sem
+
+return
+: TYPE
+|
+
+unary
+: NUM
+| NAME
+
+mulexpr
+: mulexpr '*' unary
+| mulexpr '/' unary
+| mulexpr '%' unary
+| unary
+
+
+addexpr
+: addexpr '+' mulexpr
+| addexpr '-' mulexpr
+| mulexpr
+
+compexpr
+: compexpr '>' addexpr
+| compexpr '<' addexpr
+| compexpr NOTEQ addexpr
+| addexpr
+
+
+logexpr
+: logexpr OR compexpr
+| logexpr AND compexpr
+| compexpr
+
+expr
+:
+| expr '=' logexpr
+| logexpr
+
+stmts
+:
+| stmts stmt
+
+decl
+: NAME ':' expr
+
+stmt
+: expr sem
+| '{' stmts '}'
+| decl sem
+
+args
+: NAME
+
+%%
+
+Biobuf *bin;
+
+int
+getch(void)
+{
+ int c;
+
+ c = Bgetc(bin);
+ if(c == Beof){
+ goteof = 1;
+ return -1;
+ }
+ if(c == '\n')
+ lineno++;
+ return c;
+}
+
+void
+ungetc(void)
+{
+ Bungetc(bin);
+}
+
+void
+wordlex(char *dst, int n)
+{
+ int c;
+
+ while(--n > 0){
+ c = getch();
+ if((c >= Runeself)
+ || isalnum(c)){
+ *dst++ = c;
+ continue;
+ }
+ ungetc();
+ break;
+ }
+ if(n <= 0)
+ yyerror("symbol buffer overrun");
+ *dst = '\0';
+}
+
+void
+yyerror(char *s)
+{
+ fprint(2, "%d: %s\n", lineno, s);
+ exits(s);
+}
+
+int
+yylex2(void)
+{
+ static char buf[200];
+ int c;
+ int i;
+
+Loop:
+ c = getch();
+ switch(c){
+ case -1:
+ return -1;
+ case ' ':
+ case '\t':
+ case '\n':
+ goto Loop;
+ case '/':
+ if(getch() != '*'){
+ ungetc();
+ goto Loop;
+ }
+More:
+ while((c = getch()) > 0)
+ if(c == '*')
+ break;
+ if(c != '*')
+ goto Loop;
+ if(getch() == '/')
+ goto Loop;
+ goto More;
+ }
+
+ switch(c){
+ case ';': case '=':
+ case '{': case '}':
+ case '[': case ']':
+ case '(': case ')':
+ case '+': case '-':
+ case '*': case '/':
+ case '%':
+ case '>': case '<':
+ return c;
+ }
+ ungetc();
+ wordlex(buf, sizeof buf);
+
+ if(strcmp(buf, "fn") == 0)
+ return FUNC;
+ if(strcmp(buf, "||") == 0)
+ return OR;
+ if(strcmp(buf, "&&") == 0)
+ return AND;
+
+ if(isdigit(buf[0])){
+ yylval.ival = atoi(buf);
+ return NUM;
+ }
+
+ yylval.sval = strdup(buf);
+ return NAME;
+}
+
+int
+yylex(void)
+{
+ int c;
+
+ c = yylex2();
+ return c;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ ARGBEGIN{
+ default:
+ usage();
+ break;
+ }ARGEND;
+ if(argc > 0)
+ usage();
+ bin = Bfdopen(0, OREAD);
+ goteof = 0;
+ while(!goteof)
+ yyparse();
+ Bterm(bin);
+ exits(nil);
+}