---
 src/Makefile                 |   19 +++
 src/compiler/fnp.ids         |  284 ++++++++++++++++++++++++++++++++++++++++++
 src/compiler/fpvm.c          |   67 ++++++++++
 src/compiler/idgen           |   57 +++++++++
 src/compiler/parser.y        |  169 +++++++++++++++++++++++++
 src/compiler/parser_helper.c |   77 ++++++++++++
 src/compiler/parser_helper.h |   26 ++++
 src/compiler/parser_itf.h    |   33 +++++
 src/compiler/scanner.h       |   46 +++++++
 src/compiler/scanner.re      |  122 ++++++++++++++++++
 src/compiler/unique.c        |  137 ++++++++++++++++++++
 src/compiler/unique.h        |   18 +++
 12 files changed, 1055 insertions(+), 0 deletions(-)
 create mode 100644 src/compiler/fnp.ids
 create mode 100644 src/compiler/fpvm.c
 create mode 100755 src/compiler/idgen
 create mode 100644 src/compiler/parser.y
 create mode 100644 src/compiler/parser_helper.c
 create mode 100644 src/compiler/parser_helper.h
 create mode 100644 src/compiler/parser_itf.h
 create mode 100644 src/compiler/scanner.h
 create mode 100644 src/compiler/scanner.re
 create mode 100644 src/compiler/unique.c
 create mode 100644 src/compiler/unique.h
 create mode 100644 src/obj/compiler/.keep_me

diff --git a/src/Makefile b/src/Makefile
index 87b235c..635ec45 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -35,6 +35,8 @@ OBJS += $(addprefix translations/,french.o german.o)
 OBJS += $(addprefix renderer/,framedescriptor.o analyzer.o sampler.o \
        compiler.o eval.o line.o wave.o font.o osd.o raster.o renderer.o \
        videoinreconf.o)
+OBJS += $(addprefix compiler/,fpvm.o parser_helper.o scanner.o parser.o \
+       unique.o)
 
 POBJS=$(addprefix $(OBJDIR)/,$(OBJS))
 
@@ -54,6 +56,20 @@ $(BINDIR)/flickernoise: $(POBJS)
 bandfilters.h: bandfilters.sce
        scilab -nw -nwni -nogui -nb -f bandfilters.sce
 
+%.c: %.re
+       re2c -o $@ $<
+
+%.c: %.y
+       lemon $<
+
+%.h %.inc: %.ids
+       cd compiler && ./idgen `basename $<`
+
+compiler/parser.h: compiler/parser.c
+obj/compiler/scanner.o: compiler/parser.h
+obj/compiler/parser_helper.o: compiler/parser.h
+obj/compiler/unique.o: compiler/fnp.inc
+
 # boot images for Milkymist One
 $(BINDIR)/flickernoise.bin: $(BINDIR)/flickernoise
        $(OBJCOPY) -O binary $< $@
@@ -80,5 +96,8 @@ clean:
        rm -f $(BINDIR)/flickernoise.lzma $(BINDIR)/flickernoise.fbi \
            $(BINDIR)/flickernoise.fbiz 
        rm -f $(POBJS)
+       rm -f compiler/scanner.c
+       rm -f compiler/parser.c compiler/parser.h compiler/parser.out
+       rm -f compiler/fnp.h compiler/fnp.inc
 
 .PHONY: clean load flash
diff --git a/src/compiler/fnp.ids b/src/compiler/fnp.ids
new file mode 100644
index 0000000..a310be1
--- /dev/null
+++ b/src/compiler/fnp.ids
@@ -0,0 +1,284 @@
+#
+# fnp.ids - Identifiers we already know Flickernoise will use
+#
+# We sort this list at compile time and can then perform a quick O(M*log N)
+# search on it, with M being the average length of an identifier and N the
+# number of identifiers in this list.
+#
+# User-defined identifiers and identifiers omitted from fnp.ids for any
+# other reason currently go to a linear list where they're searched in
+# O(M*N) time.
+#
+
+#
+# Built-in functions
+#
+
+above
+abs
+below
+cos
+equal
+f2i
+icos
+i2f
+if
+int
+invsqrt
+isin
+max
+min
+quake
+sin
+sqr
+sqrt
+tsign
+
+#
+#
+# Per-Frame Variables
+#
+
+sx
+sy
+cx
+cy
+rot
+dx
+dy
+zoom
+decay
+wave_mode
+wave_scale
+wave_additive
+wave_usedots
+wave_brighten
+wave_thick
+wave_x
+wave_y
+wave_r
+wave_g
+wave_b
+wave_a
+
+ob_size
+ob_r
+ob_g
+ob_b
+ob_a
+ib_size
+ib_r
+ib_g
+ib_b
+ib_a
+
+nMotionVectorsY
+mv_dx
+mv_dy
+mv_l
+mv_r
+mv_g
+mv_b
+mv_a
+
+bTexWrap
+
+time
+bass
+mid
+treb
+bass_att
+mid_att
+treb_att
+
+warp
+fWarpAnimSpeed
+fWarpScale
+
+q1
+q2
+q3
+q4
+q5
+q6
+q7
+q8
+
+fVideoEchoAlpha
+fVideoEchoZoom
+nVideoEchoOrientation
+
+dmx1
+dmx2
+dmx3
+dmx4
+dmx5
+dmx6
+dmx7
+dmx8
+
+idmx1
+idmx2
+idmx3
+idmx4
+idmx5
+idmx6
+idmx7
+idmx8
+
+osc1
+osc2
+osc3
+osc4
+
+midi1
+midi2
+midi3
+midi4
+midi5
+midi6
+midi7
+midi8
+
+video_a
+
+image1_a
+image1_x
+image1_y
+image1_zoom
+image2_a
+image2_x
+image2_y
+image2_zoom
+
+#
+# Aliases
+#
+
+fDecay
+nWaveMode
+fWaveScale
+bAdditiveWaves
+bWaveDots
+bMaximizeWaveColor
+bWaveThick
+fWaveAlpha
+
+#
+# Per-Vertex Variables
+#
+
+# System
+
+_texsize
+_hmeshsize
+_vmeshsize
+
+# MilkDrop
+
+sx
+sy
+cx
+cy
+rot
+dx
+dy
+zoom
+
+time
+bass
+mid
+treb
+bass_att
+mid_att
+treb_att
+
+warp
+fWarpAnimSpeed
+fWarpScale
+
+q1
+q2
+q3
+q4
+q5
+q6
+q7
+q8
+
+idmx1
+idmx2
+idmx3
+idmx4
+idmx5
+idmx6
+idmx7
+idmx8
+
+osc1
+osc2
+osc3
+osc4
+
+midi1
+midi2
+midi3
+midi4
+midi5
+midi6
+midi7
+midi8
+
+#
+# FPVM internal variables
+#
+
+_Xo
+_Yo
+_Xi
+_Yi
+
+#
+# PVV internal variables
+#
+
+# Initialization
+
+x
+y
+rad
+
+# Zoom
+
+_invzoom
+_xy
+_yz
+
+# Scale
+
+_xs
+_ys
+
+# Warp
+
+_warptime
+_invwarpscale
+_f0
+_f1
+_f2
+_f3
+_ox2
+_oy2
+_xw
+_yw
+
+# Rotate
+
+_cosr
+_sinr
+_u
+_v
+_xr
+_yr
+_xd
+_yd
diff --git a/src/compiler/fpvm.c b/src/compiler/fpvm.c
new file mode 100644
index 0000000..bf1ca1f
--- /dev/null
+++ b/src/compiler/fpvm.c
@@ -0,0 +1,67 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include <fpvm/fpvm.h>
+#include <fpvm/ast.h>
+
+#include "unique.h"
+#include "parser_helper.h"
+
+
+/* @@@ move later */
+int fpvm_do_assign(struct fpvm_fragment *fragment, const char *dest,
+    struct ast_node *n);
+void fpvm_do_init(struct fpvm_fragment *fragment, int vector_mode);
+
+
+void fpvm_init(struct fpvm_fragment *fragment, int vector_mode)
+{
+       /*
+        * We need to pass these through unique() because fpvm_assign does
+        * the same. Once things are in Flickernoise, we can get rid of these
+        * calls to unique().
+        */
+
+       _Xi = unique("_Xi");
+       _Xo = unique("_Xo");
+       _Yi = unique("_Yi");
+       _Yo = unique("_Yo");
+       fpvm_do_init(fragment, vector_mode);
+}
+
+
+int fpvm_assign(struct fpvm_fragment *fragment, const char *dest,
+    const char *expr)
+{
+       struct ast_node *n;
+       int res;
+
+       n = fpvm_parse(expr);
+       if(n == NULL) {
+               snprintf(fragment->last_error, FPVM_MAXERRLEN, "Parse error");
+               return 0;
+       }
+
+       dest = unique(dest);
+
+       res = fpvm_do_assign(fragment, dest, n);
+       fpvm_parse_free(n);
+
+       return res;
+}
diff --git a/src/compiler/idgen b/src/compiler/idgen
new file mode 100755
index 0000000..98069cc
--- /dev/null
+++ b/src/compiler/idgen
@@ -0,0 +1,57 @@
+#!/bin/sh -e
+#
+# idgen - Identifier table generator
+#
+# Copyright 2011 by Werner Almesberger
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, version 3 of the License.
+#
+
+
+usage()
+{
+       echo "usage: $0 file" 1>&2
+       exit 1
+}
+
+
+[ "$1" ] || usage
+[ "$2" ] && usage
+[ -r "$1" ] || { echo "$1: not found" 1&2; exit 1; }
+
+trap "echo $1.h $1.inc" 0
+
+f=`basename "$1" .ids`
+
+cat <<EOF >$f.h
+/* MACHINE-GENERATED. DO NOT EDIT ! */
+
+#ifndef        IDS_H
+#define        IDS_H
+
+extern const char *well_known[];
+
+EOF
+
+cat <<EOF >$f.inc
+/* MACHINE-GENERATED. DO NOT EDIT ! */
+
+EOF
+
+sed 's/#.*//;s/ //g;/^$/d' $1 | sort | uniq | {
+       i=0
+       while read n; do
+               echo "#define ID_$n (well_known[$i])" >>$f.h
+               echo "\"$n\"," >>$f.inc
+               i=`expr $i + 1`
+       done
+}
+
+cat <<EOF >>$f.h
+
+#endif /* !IDS_H */
+EOF
+
+trap 0
diff --git a/src/compiler/parser.y b/src/compiler/parser.y
new file mode 100644
index 0000000..6ed6b13
--- /dev/null
+++ b/src/compiler/parser.y
@@ -0,0 +1,169 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+%include {
+       #include <assert.h>
+       #include <string.h>
+       #include <stdlib.h>
+       #include <malloc.h>
+       #include <math.h>
+       #include "fpvm/ast.h"
+       #include "parser_itf.h"
+       #include "parser.h"
+
+
+       const enum ast_op tok2op[] = {
+               [TOK_IDENT]     = op_ident,
+               [TOK_CONSTANT]  = op_constant,
+               [TOK_PLUS]      = op_plus,
+               [TOK_MINUS]     = op_minus,
+               [TOK_MULTIPLY]  = op_multiply,
+               [TOK_DIVIDE]    = op_divide,
+               [TOK_PERCENT]   = op_percent,
+               [TOK_ABS]       = op_abs,
+               [TOK_ISIN]      = op_isin,
+               [TOK_ICOS]      = op_icos,
+               [TOK_SIN]       = op_sin,
+               [TOK_COS]       = op_cos,
+               [TOK_ABOVE]     = op_above,
+               [TOK_BELOW]     = op_below,
+               [TOK_EQUAL]     = op_equal,
+               [TOK_I2F]       = op_i2f,
+               [TOK_F2I]       = op_f2i,
+               [TOK_IF]        = op_if,
+               [TOK_TSIGN]     = op_tsign,
+               [TOK_QUAKE]     = op_quake,
+               [TOK_NOT]       = op_not,
+               [TOK_SQR]       = op_sqr,
+               [TOK_SQRT]      = op_sqrt,
+               [TOK_INVSQRT]   = op_invsqrt,
+               [TOK_MIN]       = op_min,
+               [TOK_MAX]       = op_max,
+               [TOK_INT]       = op_int,
+               
+       };
+
+       struct ast_node *node(int token, const char *id, struct ast_node *a,
+            struct ast_node *b, struct ast_node *c)
+       {
+               struct ast_node *n;
+
+               n = malloc(sizeof(struct ast_node));
+               n->op = tok2op[token];
+               n->label = id;
+               n->contents.branches.a = a;
+               n->contents.branches.b = b;
+               n->contents.branches.c = c;
+               return n;
+       }
+}
+
+%start_symbol start
+%extra_argument {struct ast_node **parseout}
+%token_type {struct id *}
+
+%token_destructor { free($$); }
+
+%type start {struct ast_node *}
+%type node {struct ast_node *}
+%destructor node { free($$); }
+
+start(S) ::= node(N). {
+       S = N;
+       *parseout = S;
+}
+
+node(N) ::= TOK_CONSTANT(C). {
+       N = node(TOK_CONSTANT, "", NULL, NULL, NULL);
+       N->contents.constant = C->constant;
+}
+
+node(N) ::= ident(I). {
+       N = node(I->token, I->label, NULL, NULL, NULL);
+}
+
+%left TOK_PLUS TOK_MINUS.
+%left TOK_MULTIPLY TOK_DIVIDE TOK_PERCENT.
+%left TOK_NOT.
+
+node(N) ::= node(A) TOK_PLUS node(B). {
+       N = node(TOK_PLUS, "+", A, B, NULL);
+}
+
+node(N) ::= node(A) TOK_MINUS node(B). {
+       N = node(TOK_MINUS, "-", A, B, NULL);
+}
+
+node(N) ::= node(A) TOK_MULTIPLY node(B). {
+       N = node(TOK_MULTIPLY, "*", A, B, NULL);
+}
+
+node(N) ::= node(A) TOK_DIVIDE node(B). {
+       N = node(TOK_DIVIDE, "/", A, B, NULL);
+}
+
+node(N) ::= node(A) TOK_PERCENT node(B). {
+       N = node(TOK_PERCENT, "%", A, B, NULL);
+}
+
+node(N) ::= TOK_MINUS node(A). [TOK_NOT] {
+       N = node(TOK_NOT, "!", A, NULL, NULL);
+}
+
+node(N) ::= unary(I) TOK_LPAREN node(A) TOK_RPAREN. {
+       N = node(I->token, I->label, A, NULL, NULL);
+}
+
+node(N) ::= binary(I) TOK_LPAREN node(A) TOK_COMMA node(B) TOK_RPAREN. {
+       N = node(I->token, I->label, A, B, NULL);
+}
+
+node(N) ::= ternary(I) TOK_LPAREN node(A) TOK_COMMA node(B) TOK_COMMA node(C)
+    TOK_RPAREN. {
+       N = node(I->token, I->label, A, B, C);
+}
+
+node(N) ::= TOK_LPAREN node(A) TOK_RPAREN. {
+       N = A;
+}
+
+ident(O) ::= TOK_IDENT(I).     { O = I; }
+ident(O) ::= unary(I).         { O = I; }
+ident(O) ::= binary(I).                { O = I; }
+ident(O) ::= ternary(I).       { O = I; }
+
+unary(O) ::= TOK_ABS(I).       { O = I; }
+unary(O) ::= TOK_COS(I).       { O = I; }
+unary(O) ::= TOK_F2I(I).       { O = I; }
+unary(O) ::= TOK_ICOS(I).      { O = I; }
+unary(O) ::= TOK_I2F(I).       { O = I; }
+unary(O) ::= TOK_INT(I).       { O = I; }
+unary(O) ::= TOK_INVSQRT(I).   { O = I; }
+unary(O) ::= TOK_ISIN(I).      { O = I; }
+unary(O) ::= TOK_QUAKE(I).     { O = I; }
+unary(O) ::= TOK_SIN(I).       { O = I; }
+unary(O) ::= TOK_SQR(I).       { O = I; }
+unary(O) ::= TOK_SQRT(I).      { O = I; }
+
+binary(O) ::= TOK_ABOVE(I).    { O = I; }
+binary(O) ::= TOK_BELOW(I).    { O = I; }
+binary(O) ::= TOK_EQUAL(I).    { O = I; }
+binary(O) ::= TOK_MAX(I).      { O = I; }
+binary(O) ::= TOK_MIN(I).      { O = I; }
+binary(O) ::= TOK_TSIGN(I).    { O = I; }
+
+ternary(O) ::= TOK_IF(I).      { O = I; }
diff --git a/src/compiler/parser_helper.c b/src/compiler/parser_helper.c
new file mode 100644
index 0000000..4092dc7
--- /dev/null
+++ b/src/compiler/parser_helper.c
@@ -0,0 +1,77 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <fpvm/ast.h>
+
+#include "scanner.h"
+#include "parser_itf.h"
+#include "parser_helper.h"
+
+struct ast_node *fpvm_parse(const char *expr)
+{
+       struct scanner *s;
+       int tok;
+       struct id *identifier;
+       void *p;
+       struct ast_node *ast;
+       
+       s = new_scanner((unsigned char *)expr);
+       ast = NULL;
+       p = ParseAlloc(malloc);
+       tok = scan(s);
+       while(tok != TOK_EOF) {
+               identifier = malloc(sizeof(struct id));
+               identifier->token = tok;
+               if(tok == TOK_CONSTANT) {
+                       identifier->constant = get_constant(s);
+                       identifier->label = "";
+               } else {
+                       identifier->label = get_token(s);
+               }
+               Parse(p, tok, identifier, &ast);
+               if(tok == TOK_ERROR) {
+                       printf("FPVM: scan error\n");
+                       ParseFree(p, free);
+                       delete_scanner(s);
+                       return NULL;
+               }
+               tok = scan(s);
+       }
+       Parse(p, TOK_EOF, NULL, &ast);
+       ParseFree(p, free);
+       delete_scanner(s);
+
+       if(ast == NULL) {
+               printf("FPVM: parse error\n");
+               return NULL;
+       }
+
+       return ast;
+}
+
+void fpvm_parse_free(struct ast_node *node)
+{
+       if(node == NULL) return;
+       if(node->label[0] != 0) {
+               fpvm_parse_free(node->contents.branches.a);
+               fpvm_parse_free(node->contents.branches.b);
+               fpvm_parse_free(node->contents.branches.c);
+       }
+       free(node);
+}
diff --git a/src/compiler/parser_helper.h b/src/compiler/parser_helper.h
new file mode 100644
index 0000000..d436312
--- /dev/null
+++ b/src/compiler/parser_helper.h
@@ -0,0 +1,26 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PARSER_HELPER_H
+#define __PARSER_HELPER_H
+
+#include <fpvm/ast.h>
+
+struct ast_node *fpvm_parse(const char *expr);
+void fpvm_parse_free(struct ast_node *node);
+
+#endif /* __PARSER_HELPER_H */
diff --git a/src/compiler/parser_itf.h b/src/compiler/parser_itf.h
new file mode 100644
index 0000000..895da5f
--- /dev/null
+++ b/src/compiler/parser_itf.h
@@ -0,0 +1,33 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PARSER_ITF_H
+#define __PARSER_ITF_H
+
+#define NDEBUG
+
+struct id {
+       int token;
+       const char *label;
+       float constant;
+};
+
+void *ParseAlloc(void *(*mallocProc)(size_t));
+void ParseFree(void *p, void (*freeProc)(void*));
+void Parse(void *yyp, int yymajor, struct id *yyminor, struct ast_node **p);
+
+#endif /* __PARSER_ITF_H */
diff --git a/src/compiler/scanner.h b/src/compiler/scanner.h
new file mode 100644
index 0000000..627364a
--- /dev/null
+++ b/src/compiler/scanner.h
@@ -0,0 +1,46 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SCANNER_H
+#define __SCANNER_H
+
+#define TOK_ERROR      (-1)
+#define TOK_EOF                0
+
+#include "parser.h"
+
+struct scanner {
+       unsigned char *marker;
+       unsigned char *old_cursor;
+       unsigned char *cursor;
+       unsigned char *limit;
+};
+
+struct scanner *new_scanner(unsigned char *input);
+void delete_scanner(struct scanner *s);
+
+/* get to the next token and return its type */
+int scan(struct scanner *s);
+
+/* get the unique string comprising the current token
+ */
+const char *get_token(struct scanner *s);
+
+float get_constant(struct scanner *s);
+
+#endif /* __SCANNER_H */
+
diff --git a/src/compiler/scanner.re b/src/compiler/scanner.re
new file mode 100644
index 0000000..1362ab4
--- /dev/null
+++ b/src/compiler/scanner.re
@@ -0,0 +1,122 @@
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "unique.h"
+#include "scanner.h"
+
+#define YYCTYPE     unsigned char
+#define YYCURSOR    s->cursor
+#define YYLIMIT     s->limit
+
+/* refilling not supported */
+#define YYMARKER s->marker
+#define YYFILL(n)
+
+struct scanner *new_scanner(unsigned char *input)
+{
+       struct scanner *s;
+       
+       s = malloc(sizeof(struct scanner));
+       if(s == NULL) return NULL;
+       
+       s->marker = input;
+       s->old_cursor = input;
+       s->cursor = input;
+       s->limit = input + strlen((char *)input);
+       
+       return s;
+}
+
+void delete_scanner(struct scanner *s)
+{
+       free(s);
+}
+
+int scan(struct scanner *s)
+{
+       std:
+       if(s->cursor == s->limit) return TOK_EOF;
+       s->old_cursor = s->cursor;
+       
+       /*!re2c
+               [\x20\r\t]              { goto std; }
+               [0-9]+                  { return TOK_CONSTANT; }
+               [0-9]* "." [0-9]*       { return TOK_CONSTANT; }
+
+               "above"                 { return TOK_ABOVE; }
+               "abs"                   { return TOK_ABS; }
+               "below"                 { return TOK_BELOW; }
+               "cos"                   { return TOK_COS; }
+               "equal"                 { return TOK_EQUAL; }
+               "f2i"                   { return TOK_F2I; }
+               "icos"                  { return TOK_ICOS; }
+               "i2f"                   { return TOK_I2F; }
+               "if"                    { return TOK_IF; }
+               "int"                   { return TOK_INT; }
+               "invsqrt"               { return TOK_INVSQRT; }
+               "isin"                  { return TOK_ISIN; }
+               "max"                   { return TOK_MAX; }
+               "min"                   { return TOK_MIN; }
+               "quake"                 { return TOK_QUAKE; }
+               "sin"                   { return TOK_SIN; }
+               "sqr"                   { return TOK_SQR; }
+               "sqrt"                  { return TOK_SQRT; }
+               "tsign"                 { return TOK_TSIGN; }
+
+               [a-zA-Z_0-9]+           { return TOK_IDENT; }
+               "+"                     { return TOK_PLUS; }
+               "-"                     { return TOK_MINUS; }
+               "*"                     { return TOK_MULTIPLY; }
+               "/"                     { return TOK_DIVIDE; }
+               "%"                     { return TOK_PERCENT; }
+               "("                     { return TOK_LPAREN; }
+               ")"                     { return TOK_RPAREN; }
+               ","                     { return TOK_COMMA; }
+               [\x00-\xff]             { return TOK_ERROR; }
+       */
+}
+
+const char *get_token(struct scanner *s)
+{
+       return unique_n((const char *) s->old_cursor,
+           s->cursor - s->old_cursor);
+}
+
+float get_constant(struct scanner *s)
+{
+       const unsigned char *p;
+       float v = 0;
+       float m = 1;
+
+       for(p = s->old_cursor; p != s->cursor; p++) {
+               if(*p == '.')
+                       goto dot;
+               v = v*10+(*p-'0');
+       }
+       return v;
+
+dot:
+       for(p++; p != s->cursor; p++) {
+               m /= 10;
+               v += m*(*p-'0');
+       }
+       return v;
+}
diff --git a/src/compiler/unique.c b/src/compiler/unique.c
new file mode 100644
index 0000000..c571f6d
--- /dev/null
+++ b/src/compiler/unique.c
@@ -0,0 +1,137 @@
+/*
+ * unique.c - Unique string store
+ *
+ * Copyright 2011 by Werner Almesberger
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "unique.h"
+
+
+#define        INITIAL_ALLOC   64
+
+
+struct key_n {
+       const char *s;
+       int n;
+};
+
+const char *well_known[] = {
+#include "fnp.inc"
+};
+
+static const char **vars = NULL;
+static int num_vars = 0, allocated = 0;
+
+
+/*
+ * "a" is not NUL-terminated and its length "a" is determined by "n".
+ * "b" is NUL-terminated.
+ */
+
+static int strcmp_n(const char *a, const char *b, int n)
+{
+       int diff;
+
+       diff = strncmp(a, b, n);
+       if (diff)
+               return diff;
+       /* handle implicit NUL in string "a" */
+       return -b[n];
+}
+
+
+static char *strdup_n(const char *s, int n)
+{
+       char *new;
+
+       new = malloc(n+1);
+       memcpy(new, s, n);
+       new[n] = 0;
+       return new;
+}
+
+
+static void grow_table(void)
+{
+       if(num_vars != allocated)
+               return;
+
+       allocated = allocated ? allocated*2 : INITIAL_ALLOC;
+       vars = realloc(vars, allocated*sizeof(*vars));
+}
+
+
+static int cmp(const void *a, const void *b)
+{
+       return strcmp(a, *(const char **) b);
+}
+
+
+static int cmp_n(const void *a, const void *b)
+{
+       const struct key_n *key = a;
+
+       return strcmp_n(key->s, *(const char **) b, key->n);
+}
+
+
+const char *unique(const char *s)
+{
+       const char **res;
+       const char **walk;
+
+       if(!isalnum(*s) && *s != '_')
+               return s;
+       res = bsearch(s, well_known, sizeof(well_known)/sizeof(*well_known),
+           sizeof(s), cmp);
+       if(res)
+               return *res;
+       for(walk = vars; walk != vars+num_vars; walk++)
+               if(!strcmp(*walk, s))
+                       return *walk;
+       grow_table();
+       return vars[num_vars++] = strdup(s);
+}
+
+
+const char *unique_n(const char *s, int n)
+{
+       struct key_n key = {
+               .s = s,
+               .n = n,
+       };
+       const char **res;
+       const char **walk;
+
+       if(!isalnum(*s) && *s != '_')
+               return s;
+       res = bsearch(&key, well_known, sizeof(well_known)/sizeof(*well_known),
+           sizeof(s), cmp_n);
+       if(res)
+               return *res;
+       for(walk = vars; walk != vars+num_vars; walk++)
+               if(!strcmp_n(s, *walk, n))
+                       return *walk;
+       grow_table();
+       return vars[num_vars++] = strdup_n(s, n);
+}
+
+
+void unique_free(void)
+{
+       int i;
+
+       for(i = 0; i != num_vars; i++)
+               free((void *) vars[i]);
+       free(vars);
+       num_vars = allocated = 0;
+}
diff --git a/src/compiler/unique.h b/src/compiler/unique.h
new file mode 100644
index 0000000..ff069ac
--- /dev/null
+++ b/src/compiler/unique.h
@@ -0,0 +1,18 @@
+/*
+ * unique.h - Unique string store
+ *
+ * Copyright 2011 by Werner Almesberger
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ */
+
+#ifndef UNIQUE_H
+#define        UNIQUE_H
+
+const char *unique(const char *s);
+const char *unique_n(const char *s, int n);
+void unique_free(void);
+
+#endif /* !UNIQUE_H */
diff --git a/src/obj/compiler/.keep_me b/src/obj/compiler/.keep_me
new file mode 100644
index 0000000..e69de29
-- 
1.7.1

_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode

Reply via email to