summaryrefslogtreecommitdiffstats
path: root/dimension
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-02-01 21:27:12 -0500
committerTavian Barnes <tavianator@gmail.com>2010-02-01 21:27:12 -0500
commit40752ebfb3ec8355b4f17681f8aab0ca7f6992f4 (patch)
treed5c1a693cc5468e2d1688fc5ee49e1ea6e7e06e1 /dimension
parent58634f3410db1ff16f6e21d9d0e1fcfaa17b2453 (diff)
downloaddimension-40752ebfb3ec8355b4f17681f8aab0ca7f6992f4.tar.xz
Implement #declare, #local, and #undef in middle tier.
Oh God this is ugly...
Diffstat (limited to 'dimension')
-rw-r--r--dimension/Makefile.am33
-rw-r--r--dimension/common.declarations31
-rw-r--r--dimension/common.nonterminals75
-rw-r--r--dimension/common.prologue145
-rw-r--r--dimension/common.rules506
-rw-r--r--dimension/common.terminals (renamed from dimension/grammar.terminals)0
-rw-r--r--dimension/directives.declarations26
-rw-r--r--dimension/directives.epilogue0
-rw-r--r--dimension/directives.nonterminals20
-rw-r--r--dimension/directives.prologue34
-rw-r--r--dimension/directives.rules35
-rw-r--r--dimension/grammar.declarations11
-rw-r--r--dimension/grammar.epilogue1
-rw-r--r--dimension/grammar.nonterminals58
-rw-r--r--dimension/grammar.prologue127
-rw-r--r--dimension/grammar.rules524
-rw-r--r--dimension/lexer.l1
-rw-r--r--dimension/tokenize.c207
-rw-r--r--dimension/tokenize.h13
19 files changed, 1116 insertions, 731 deletions
diff --git a/dimension/Makefile.am b/dimension/Makefile.am
index 1ee125c..6335ce7 100644
--- a/dimension/Makefile.am
+++ b/dimension/Makefile.am
@@ -22,25 +22,42 @@ INCLUDES = -I$(top_srcdir)/libdimension
bin_PROGRAMS = dimension
AM_YFLAGS = -d
-BUILT_SOURCES = grammar.h
-EXTRA_DIST = grammar.prologue \
+BUILT_SOURCES = directives.h grammar.h
+EXTRA_DIST = common.prologue \
+ common.declarations \
+ common.terminals \
+ common.nonterminals \
+ common.rules \
+ directives.prologue \
+ directives.declarations \
+ directives.nonterminals \
+ directives.rules \
+ grammar.prologue \
grammar.declarations \
- grammar.terminals \
grammar.nonterminals \
grammar.rules \
grammar.epilogue
-grammar.y: grammar.prologue grammar.declarations grammar.terminals grammar.nonterminals grammar.rules grammar.epilogue
+grammar.y: grammar.prologue grammar.declarations grammar.nonterminals grammar.rules grammar.epilogue common.prologue common.declarations common.terminals common.nonterminals common.rules
echo "%{" >$@
- cat grammar.prologue >>$@
+ cat {common,grammar}.prologue >>$@
echo "%}" >>$@
- cat grammar.{declarations,terminals,nonterminals} >>$@
+ cat common.terminals {grammar,common}.{declarations,nonterminals} >>$@
echo "%%" >>$@
- cat grammar.rules >>$@
+ cat grammar.rules common.rules >>$@
echo "%%" >>$@
cat grammar.epilogue >>$@
-dimension_SOURCES = grammar.y \
+directives.y: directives.prologue directives.declarations directives.nonterminals directives.rules common.prologue common.declarations common.terminals common.nonterminals common.rules
+ echo "%{" >$@
+ cat {common,directives}.prologue >>$@
+ echo "%}" >>$@
+ cat common.terminals {directives,common}.{declarations,nonterminals} >>$@
+ echo "%%" >>$@
+ cat directives.rules common.rules >>$@
+
+dimension_SOURCES = directives.y \
+ grammar.y \
lexer.l \
main.c \
parse.c \
diff --git a/dimension/common.declarations b/dimension/common.declarations
new file mode 100644
index 0000000..7e31f5b
--- /dev/null
+++ b/dimension/common.declarations
@@ -0,0 +1,31 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of Dimension. *
+ * *
+ * Dimension 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; either version 3 of the License, or (at *
+ * your option) any later version. *
+ * *
+ * Dimension 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/>. *
+ *************************************************************************/
+
+%define api.pure
+%locations
+%error-verbose
+
+%glr-parser
+
+%lex-param {const char *filename}
+%lex-param {dmnsn_symbol_table *symtable}
+%lex-param {void *yyscanner}
+
+%destructor { free($$); } <value>
+%destructor { dmnsn_delete_astnode($$); } <astnode>
diff --git a/dimension/common.nonterminals b/dimension/common.nonterminals
new file mode 100644
index 0000000..48e7335
--- /dev/null
+++ b/dimension/common.nonterminals
@@ -0,0 +1,75 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of Dimension. *
+ * *
+ * Dimension 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; either version 3 of the License, or (at *
+ * your option) any later version. *
+ * *
+ * Dimension 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/>. *
+ *************************************************************************/
+
+/* Identifiers */
+%type <astnode> IDENTIFIER
+
+/* Transformations */
+%type <astnode> TRANSFORMATION
+
+/* The camera */
+%type <astnode> CAMERA
+%type <astnode> CAMERA_ITEMS
+%type <astnode> CAMERA_ITEM
+%type <astnode> CAMERA_TYPE
+%type <astnode> CAMERA_VECTOR
+%type <astnode> CAMERA_MODIFIER
+
+/* Objects */
+%type <astnode> OBJECT
+%type <astnode> FINITE_SOLID_OBJECT
+%type <astnode> BOX
+%type <astnode> LIGHT_SOURCE
+%type <astnode> SPHERE
+
+/* Object modifiers */
+%type <astnode> OBJECT_MODIFIERS
+%type <astnode> OBJECT_MODIFIER
+
+/* Textures */
+%type <astnode> TEXTURE
+%type <astnode> TEXTURE_ITEMS
+
+/* Pigments */
+%type <astnode> PIGMENT
+%type <astnode> PIGMENT_TYPE
+
+/* Finishes */
+%type <astnode> FINISH
+%type <astnode> FINISH_ITEMS
+%type <astnode> REFLECTION
+%type <astnode> REFLECTION_ITEMS
+
+/* Floats */
+%type <astnode> FLOAT
+%type <astnode> FLOAT_LITERAL
+
+/* Vectors */
+%type <astnode> VECTOR
+%type <astnode> VECTOR_LITERAL
+
+/* Generalized arithmetic expressions */
+%type <astnode> ARITH_EXPR
+
+/* Colors */
+%type <astnode> COLOR
+%type <astnode> COLOR_BODY
+%type <astnode> COLOR_VECTOR
+%type <astnode> COLOR_KEYWORD_GROUP
+%type <astnode> COLOR_KEYWORD_GROUP_INIT
diff --git a/dimension/common.prologue b/dimension/common.prologue
new file mode 100644
index 0000000..11ab99c
--- /dev/null
+++ b/dimension/common.prologue
@@ -0,0 +1,145 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of Dimension. *
+ * *
+ * Dimension 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; either version 3 of the License, or (at *
+ * your option) any later version. *
+ * *
+ * Dimension 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 "parse.h"
+#include "tokenize.h"
+#include "utility.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+#define YYSTYPE dmnsn_parse_item
+#define YYLTYPE dmnsn_parse_location
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do { \
+ if (N) { \
+ (Current).first_filename = YYRHSLOC(Rhs, 1).first_filename; \
+ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
+ (Current).last_filename = YYRHSLOC(Rhs, N).last_filename; \
+ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC(Rhs, N).last_column; \
+ } else { \
+ (Current).first_filename = (Current).last_filename = \
+ YYRHSLOC(Rhs, 0).last_filename; \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC(Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC(Rhs, 0).last_column; \
+ } \
+ } while (0)
+
+/* Create a new astnode, populating filename, line, and col */
+
+static dmnsn_astnode
+dmnsn_new_astnode(dmnsn_astnode_type type, YYLTYPE lloc)
+{
+ dmnsn_astnode astnode = {
+ .type = type,
+ .children = dmnsn_new_array(sizeof(dmnsn_astnode)),
+ .ptr = NULL,
+ .refcount = malloc(sizeof(unsigned int)),
+ .filename = lloc.first_filename,
+ .line = lloc.first_line,
+ .col = lloc.first_column
+ };
+
+ if (!astnode.refcount) {
+ dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate reference count.");
+ }
+ *astnode.refcount = 1;
+
+ return astnode;
+}
+
+/* Semi-shallow copy */
+static void
+dmnsn_copy_children(dmnsn_astnode dest, dmnsn_astnode src)
+{
+ unsigned int i;
+ for (i = 0; i < dmnsn_array_size(src.children); ++i) {
+ dmnsn_astnode node;
+ dmnsn_array_get(src.children, i, &node);
+ ++*node.refcount;
+
+ if (i < dmnsn_array_size(dest.children)) {
+ dmnsn_astnode clobbered;
+ dmnsn_array_get(dest.children, i, &clobbered);
+ dmnsn_delete_astnode(clobbered);
+ }
+
+ dmnsn_array_set(dest.children, i, &node);
+ }
+}
+
+static dmnsn_astnode
+dmnsn_new_astnode1(dmnsn_astnode_type type, YYLTYPE lloc, dmnsn_astnode n1)
+{
+ dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
+ dmnsn_array_push(astnode.children, &n1);
+ return astnode;
+}
+
+static dmnsn_astnode
+dmnsn_new_astnode2(dmnsn_astnode_type type, YYLTYPE lloc,
+ dmnsn_astnode n1, dmnsn_astnode n2)
+{
+ dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
+ dmnsn_array_push(astnode.children, &n1);
+ dmnsn_array_push(astnode.children, &n2);
+ return astnode;
+}
+
+static dmnsn_astnode
+dmnsn_new_astnode3(dmnsn_astnode_type type, YYLTYPE lloc,
+ dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3)
+{
+ dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
+ dmnsn_array_push(astnode.children, &n1);
+ dmnsn_array_push(astnode.children, &n2);
+ dmnsn_array_push(astnode.children, &n3);
+ return astnode;
+}
+
+static dmnsn_astnode
+dmnsn_new_astnode4(dmnsn_astnode_type type, YYLTYPE lloc,
+ dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3,
+ dmnsn_astnode n4)
+{
+ dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
+ dmnsn_array_push(astnode.children, &n1);
+ dmnsn_array_push(astnode.children, &n2);
+ dmnsn_array_push(astnode.children, &n3);
+ dmnsn_array_push(astnode.children, &n4);
+ return astnode;
+}
+
+static dmnsn_astnode
+dmnsn_new_astnode5(dmnsn_astnode_type type, YYLTYPE lloc,
+ dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3,
+ dmnsn_astnode n4, dmnsn_astnode n5)
+{
+ dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
+ dmnsn_array_push(astnode.children, &n1);
+ dmnsn_array_push(astnode.children, &n2);
+ dmnsn_array_push(astnode.children, &n3);
+ dmnsn_array_push(astnode.children, &n4);
+ dmnsn_array_push(astnode.children, &n5);
+ return astnode;
+}
diff --git a/dimension/common.rules b/dimension/common.rules
new file mode 100644
index 0000000..ef4b3dd
--- /dev/null
+++ b/dimension/common.rules
@@ -0,0 +1,506 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of Dimension. *
+ * *
+ * Dimension 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; either version 3 of the License, or (at *
+ * your option) any later version. *
+ * *
+ * Dimension 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/>. *
+ *************************************************************************/
+
+/* Identifiers */
+
+IDENTIFIER: "identifier" {
+ $$ = dmnsn_new_astnode(DMNSN_AST_IDENTIFIER, @$);
+ $$.ptr = $1;
+ }
+;
+
+/* Transformations */
+
+TRANSFORMATION: "rotate" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_ROTATION, @$, $2);
+ }
+ | "scale" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_SCALE, @$, $2);
+ }
+ | "translate" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSLATION, @$, $2);
+ }
+;
+
+/* Cameras */
+
+CAMERA: "camera" "{"
+ CAMERA_ITEMS
+ "}"
+ {
+ $$ = $3;
+ }
+;
+
+CAMERA_ITEMS: /* empty */ {
+ $$ = dmnsn_new_astnode(DMNSN_AST_CAMERA, @$);
+ }
+ | CAMERA_ITEMS CAMERA_ITEM {
+ $$ = $1;
+ dmnsn_array_push($$.children, &$2);
+ }
+;
+
+CAMERA_ITEM: CAMERA_TYPE
+ | CAMERA_VECTOR
+ | CAMERA_MODIFIER
+;
+
+CAMERA_TYPE: "perspective" {
+ $$ = dmnsn_new_astnode(DMNSN_AST_PERSPECTIVE, @$);
+ }
+;
+
+CAMERA_VECTOR: "location" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_LOCATION, @$, $2);
+ }
+ | "right" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_RIGHT, @$, $2);
+ }
+ | "up" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_UP, @$, $2);
+ }
+ | "sky" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_SKY, @$, $2);
+ }
+ | "direction" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DIRECTION, @$, $2);
+ }
+;
+
+CAMERA_MODIFIER: "angle" FLOAT {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_ANGLE, @$, $2);
+ }
+ | "look_at" VECTOR {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_LOOK_AT, @$, $2);
+ }
+ | TRANSFORMATION
+;
+
+/* Objects */
+
+OBJECT: FINITE_SOLID_OBJECT
+ | LIGHT_SOURCE
+;
+
+FINITE_SOLID_OBJECT: BOX
+ | SPHERE
+;
+
+BOX: "box" "{"
+ VECTOR "," VECTOR
+ OBJECT_MODIFIERS
+ "}"
+ {
+ $$ = dmnsn_new_astnode3(DMNSN_AST_BOX, @$, $3, $5, $6);
+ }
+;
+
+LIGHT_SOURCE: "light_source" "{"
+ VECTOR "," COLOR
+ "}"
+ {
+ $$ = dmnsn_new_astnode2(DMNSN_AST_LIGHT_SOURCE, @$, $3, $5);
+ }
+;
+
+SPHERE: "sphere" "{"
+ VECTOR "," FLOAT
+ OBJECT_MODIFIERS
+ "}"
+ {
+ $$ = dmnsn_new_astnode3(DMNSN_AST_SPHERE, @$, $3, $5, $6);
+ }
+;
+
+/* Object modifiers */
+
+OBJECT_MODIFIERS: /* empty */ {
+ $$ = dmnsn_new_astnode(DMNSN_AST_OBJECT_MODIFIERS, @$);
+ }
+ | OBJECT_MODIFIERS OBJECT_MODIFIER {
+ $$ = $1;
+ dmnsn_array_push($$.children, &$2);
+ }
+;
+
+OBJECT_MODIFIER: TRANSFORMATION
+ | TEXTURE
+ | PIGMENT {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_TEXTURE, @$, $1);
+ }
+;
+
+/* Textures */
+
+TEXTURE: "texture" "{"
+ TEXTURE_ITEMS
+ "}"
+ { $$ = $3; }
+;
+
+TEXTURE_ITEMS: /* empty */ {
+ $$ = dmnsn_new_astnode(DMNSN_AST_TEXTURE, @$);
+ }
+ | TEXTURE_ITEMS PIGMENT {
+ $$ = $1;
+ dmnsn_array_push($$.children, &$2);
+ }
+ | TEXTURE_ITEMS FINISH {
+ $$ = $1;
+ dmnsn_array_push($$.children, &$2);
+ }
+;
+
+/* Pigments */
+
+PIGMENT: "pigment" "{"
+ PIGMENT_TYPE
+ "}"
+ {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_PIGMENT, @$, $3);
+ }
+;
+
+PIGMENT_TYPE: /* empty */ {
+ $$ = dmnsn_new_astnode(DMNSN_AST_NONE, @$);
+ }
+ | COLOR
+;
+
+/* Finishes */
+FINISH: "finish" "{"
+ FINISH_ITEMS
+ "}"
+ { $$ = $3; }
+;
+
+FINISH_ITEMS: /* empty */ {
+ $$ = dmnsn_new_astnode(DMNSN_AST_FINISH, @$);
+ }
+ | FINISH_ITEMS "ambient" COLOR {
+ dmnsn_astnode ambient = dmnsn_new_astnode1(DMNSN_AST_AMBIENT,
+ @2, $3);
+ $$ = $1;
+ dmnsn_array_push($$.children, &ambient);
+ }
+ | FINISH_ITEMS "diffuse" FLOAT {
+ dmnsn_astnode diffuse = dmnsn_new_astnode1(DMNSN_AST_DIFFUSE,
+ @2, $3);
+ $$ = $1;
+ dmnsn_array_push($$.children, &diffuse);
+ }
+ | FINISH_ITEMS "phong" FLOAT {
+ dmnsn_astnode phong = dmnsn_new_astnode1(DMNSN_AST_PHONG, @2, $3);
+ $$ = $1;
+ dmnsn_array_push($$.children, &phong);
+ }
+ | FINISH_ITEMS "phong_size" FLOAT {
+ dmnsn_astnode phong_size
+ = dmnsn_new_astnode1(DMNSN_AST_PHONG_SIZE, @2, $3);
+ $$ = $1;
+ dmnsn_array_push($$.children, &phong_size);
+ }
+ | FINISH_ITEMS REFLECTION {
+ $$ = $1;
+ dmnsn_array_push($$.children, &$2);
+ }
+;
+
+REFLECTION: "reflection" "{"
+ COLOR
+ REFLECTION_ITEMS
+ "}"
+ {
+ ++*$3.refcount;
+ $$ = dmnsn_new_astnode3(DMNSN_AST_REFLECTION, @$, $3, $3, $4);
+ }
+ | "reflection" "{"
+ COLOR "," COLOR
+ REFLECTION_ITEMS
+ "}"
+ {
+ $$ = dmnsn_new_astnode3(DMNSN_AST_REFLECTION, @$, $3, $5, $6);
+ }
+;
+
+REFLECTION_ITEMS: /* empty */ {
+ $$ = dmnsn_new_astnode(DMNSN_AST_REFLECTION_ITEMS, @$);
+ }
+ | REFLECTION_ITEMS "falloff" FLOAT {
+ dmnsn_astnode falloff
+ = dmnsn_new_astnode1(DMNSN_AST_FALLOFF, @2, $3);
+ $$ = $1;
+ dmnsn_array_push($$.children, &falloff);
+ }
+;
+
+/* Floats */
+
+FLOAT: ARITH_EXPR {
+ $$ = dmnsn_eval_scalar($1, symtable);
+ dmnsn_delete_astnode($1);
+
+ if ($$.type == DMNSN_AST_NONE) {
+ dmnsn_delete_astnode($$);
+ YYERROR;
+ }
+ }
+;
+
+FLOAT_LITERAL: "integer" {
+ $$ = dmnsn_new_astnode(DMNSN_AST_INTEGER, @$);
+ $$.ptr = malloc(sizeof(long));
+ if (!$$.ptr)
+ dmnsn_error(DMNSN_SEVERITY_HIGH,
+ "Failed to allocate room for integer.");
+
+ *(long *)$$.ptr = strtol($1, NULL, 0);
+ free($1);
+ }
+ | "float" {
+ $$ = dmnsn_new_astnode(DMNSN_AST_FLOAT, @$);
+ $$.ptr = malloc(sizeof(double));
+ if (!$$.ptr)
+ dmnsn_error(DMNSN_SEVERITY_HIGH,
+ "Failed to allocate room for float.");
+
+ *(double *)$$.ptr = strtod($1, NULL);
+ free($1);
+ }
+;
+
+/* Vectors */
+
+VECTOR: ARITH_EXPR {
+ $$ = dmnsn_eval_vector($1, symtable);
+ dmnsn_delete_astnode($1);
+
+ if ($$.type == DMNSN_AST_NONE) {
+ dmnsn_delete_astnode($$);
+ YYERROR;
+ }
+ }
+;
+
+VECTOR_LITERAL: "<" ARITH_EXPR "," ARITH_EXPR ">" {
+ $$ = dmnsn_new_astnode2(DMNSN_AST_VECTOR, @$, $2, $4);
+ }
+ | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ">" {
+ $$ = dmnsn_new_astnode3(DMNSN_AST_VECTOR, @$, $2, $4, $6);
+ }
+ | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ","
+ ARITH_EXPR ">" {
+ $$ = dmnsn_new_astnode4(DMNSN_AST_VECTOR, @$, $2, $4, $6, $8);
+ }
+ | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ","
+ ARITH_EXPR "," ARITH_EXPR ">" {
+ $$ = dmnsn_new_astnode5(DMNSN_AST_VECTOR, @$,
+ $2, $4, $6, $8, $10);
+ }
+;
+
+/* Generalized arithmetic expressions */
+
+ARITH_EXPR: FLOAT_LITERAL
+ | VECTOR_LITERAL
+ | ARITH_EXPR "+" ARITH_EXPR {
+ $$ = dmnsn_new_astnode2(DMNSN_AST_ADD, @$, $1, $3);
+ }
+ | ARITH_EXPR "-" ARITH_EXPR {
+ $$ = dmnsn_new_astnode2(DMNSN_AST_SUB, @$, $1, $3);
+ }
+ | ARITH_EXPR "*" ARITH_EXPR {
+ $$ = dmnsn_new_astnode2(DMNSN_AST_MUL, @$, $1, $3);
+ }
+ | ARITH_EXPR "/" ARITH_EXPR {
+ $$ = dmnsn_new_astnode2(DMNSN_AST_DIV, @$, $1, $3);
+ }
+ | "+" ARITH_EXPR %prec DMNSN_T_NEGATE { $$ = $2; }
+ | "-" ARITH_EXPR %prec DMNSN_T_NEGATE {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_NEGATE, @$, $2);
+ }
+ | ARITH_EXPR "." "x" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1);
+ }
+ | ARITH_EXPR "." "u" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1);
+ }
+ | ARITH_EXPR "." "red" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1);
+ }
+ | ARITH_EXPR "." "y" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1);
+ }
+ | ARITH_EXPR "." "v" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1);
+ }
+ | ARITH_EXPR "." "green" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1);
+ }
+ | ARITH_EXPR "." "z" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Z, @$, $1);
+ }
+ | ARITH_EXPR "." "blue" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Z, @$, $1);
+ }
+ | ARITH_EXPR "." "t" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_T, @$, $1);
+ }
+ | ARITH_EXPR "." "filter" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_T, @$, $1);
+ }
+ | ARITH_EXPR "." "transmit" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_TRANSMIT, @$, $1);
+ }
+ | "(" ARITH_EXPR ")" { $$ = $2; }
+ | IDENTIFIER
+;
+
+/* Colors */
+
+COLOR: COLOR_BODY {
+ $$ = $1;
+ $$.type = DMNSN_AST_COLOR;
+ }
+ | "color" COLOR_BODY {
+ $$ = $2;
+ $$.type = DMNSN_AST_COLOR;
+ }
+;
+
+COLOR_BODY: COLOR_VECTOR %dprec 1
+ | COLOR_KEYWORD_GROUP %dprec 2
+;
+
+COLOR_VECTOR: "rgb" VECTOR {
+ dmnsn_astnode f, t;
+ dmnsn_array_get($2.children, 3, &f);
+ dmnsn_array_get($2.children, 4, &t);
+ dmnsn_delete_astnode(f);
+ dmnsn_delete_astnode(t);
+
+ dmnsn_array_resize($2.children, 3);
+
+ $$ = dmnsn_eval_vector($2, symtable);
+ dmnsn_delete_astnode($2);
+ }
+ | "rgbf" VECTOR {
+ dmnsn_astnode t;
+ dmnsn_array_get($2.children, 4, &t);
+ dmnsn_delete_astnode(t);
+
+ dmnsn_array_resize($2.children, 4);
+
+ $$ = dmnsn_eval_vector($2, symtable);
+ dmnsn_delete_astnode($2);
+ }
+ | "rgbt" VECTOR {
+ /* Chop off the fifth component */
+ dmnsn_astnode t;
+ dmnsn_array_get($2.children, 4, &t);
+ dmnsn_delete_astnode(t);
+
+ dmnsn_array_resize($2.children, 4);
+
+ $$ = dmnsn_eval_vector($2, symtable);
+ dmnsn_delete_astnode($2);
+
+ /* Swap the transmit and filter components */
+ dmnsn_astnode temp;
+ dmnsn_array_get($$.children, 4, &temp);
+ dmnsn_array_set($$.children, 4, dmnsn_array_at($$.children, 3));
+ dmnsn_array_set($$.children, 3, &temp);
+ }
+ | "rgbft" VECTOR { $$ = $2; }
+ | VECTOR
+;
+
+COLOR_KEYWORD_GROUP: COLOR_KEYWORD_GROUP_INIT COLOR_KEYWORD_ITEM
+ | COLOR_KEYWORD_GROUP COLOR_KEYWORD_ITEM
+;
+
+COLOR_KEYWORD_GROUP_INIT: /* empty */ {
+ dmnsn_astnode zero =
+ dmnsn_new_astnode(DMNSN_AST_INTEGER, @$);
+ zero.ptr = malloc(sizeof(long));
+ if (!zero.ptr)
+ dmnsn_error(DMNSN_SEVERITY_HIGH,
+ "Failed to allocate room for integer.");
+ *(long *)zero.ptr = 0;
+
+ $$ = dmnsn_eval_vector(zero, symtable);
+ dmnsn_delete_astnode(zero);
+ }
+;
+
+COLOR_KEYWORD_ITEM: "identifier" {
+ dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, $1);
+ if (!symbol) {
+ dmnsn_diagnostic(@1.first_filename, @1.first_line,
+ @1.first_column,
+ "unbound identifier '%s'", $1);
+ free($1);
+ YYERROR;
+ } else if (symbol->type != DMNSN_AST_COLOR) {
+ dmnsn_astnode eval = dmnsn_eval_vector(*symbol, symtable);
+ if (eval.type == DMNSN_AST_NONE) {
+ free($1);
+ YYERROR;
+ }
+
+ dmnsn_copy_children($<astnode>0, eval);
+ dmnsn_delete_astnode(eval);
+ } else {
+ dmnsn_copy_children($<astnode>0, *symbol);
+ }
+
+ free($1);
+ }
+ | "red" FLOAT {
+ dmnsn_astnode old;
+ dmnsn_array_get($<astnode>0.children, 0, &old);
+ dmnsn_array_set($<astnode>0.children, 0, &$2);
+ dmnsn_delete_astnode(old);
+ }
+ | "green" FLOAT {
+ dmnsn_astnode old;
+ dmnsn_array_get($<astnode>0.children, 1, &old);
+ dmnsn_array_set($<astnode>0.children, 1, &$2);
+ dmnsn_delete_astnode(old);
+ }
+ | "blue" FLOAT {
+ dmnsn_astnode old;
+ dmnsn_array_get($<astnode>0.children, 2, &old);
+ dmnsn_array_set($<astnode>0.children, 2, &$2);
+ dmnsn_delete_astnode(old);
+ }
+ | "filter" FLOAT {
+ dmnsn_astnode old;
+ dmnsn_array_get($<astnode>0.children, 3, &old);
+ dmnsn_array_set($<astnode>0.children, 3, &$2);
+ dmnsn_delete_astnode(old);
+ }
+ | "transmit" FLOAT {
+ dmnsn_astnode old;
+ dmnsn_array_get($<astnode>0.children, 4, &old);
+ dmnsn_array_set($<astnode>0.children, 4, &$2);
+ dmnsn_delete_astnode(old);
+ }
+;
diff --git a/dimension/grammar.terminals b/dimension/common.terminals
index 37d3c16..37d3c16 100644
--- a/dimension/grammar.terminals
+++ b/dimension/common.terminals
diff --git a/dimension/directives.declarations b/dimension/directives.declarations
new file mode 100644
index 0000000..0543b3d
--- /dev/null
+++ b/dimension/directives.declarations
@@ -0,0 +1,26 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of Dimension. *
+ * *
+ * Dimension 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; either version 3 of the License, or (at *
+ * your option) any later version. *
+ * *
+ * Dimension 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/>. *
+ *************************************************************************/
+
+%name-prefix "dmnsn_ld_yy"
+
+%expect 9
+
+%parse-param {const char *filename}
+%parse-param {void *yyscanner}
+%parse-param {dmnsn_symbol_table *symtable}
diff --git a/dimension/directives.epilogue b/dimension/directives.epilogue
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dimension/directives.epilogue
diff --git a/dimension/directives.nonterminals b/dimension/directives.nonterminals
new file mode 100644
index 0000000..ac23a0a
--- /dev/null
+++ b/dimension/directives.nonterminals
@@ -0,0 +1,20 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of Dimension. *
+ * *
+ * Dimension 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; either version 3 of the License, or (at *
+ * your option) any later version. *
+ * *
+ * Dimension 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/>. *
+ *************************************************************************/
+
+%type <astnode> RVALUE
diff --git a/dimension/directives.prologue b/dimension/directives.prologue
new file mode 100644
index 0000000..9bbcafc
--- /dev/null
+++ b/dimension/directives.prologue
@@ -0,0 +1,34 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of Dimension. *
+ * *
+ * Dimension 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; either version 3 of the License, or (at *
+ * your option) any later version. *
+ * *
+ * Dimension 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/>. *
+ *************************************************************************/
+
+void
+yyerror(YYLTYPE *locp, const char *filename, void *yyscanner,
+ dmnsn_symbol_table *symtable, const char *str)
+{
+ dmnsn_diagnostic(locp->first_filename, locp->first_line, locp->first_column,
+ "%s", str);
+}
+
+static int
+dmnsn_ld_yylex(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp,
+ const char *filename, dmnsn_symbol_table *symtable,
+ void *yyscanner)
+{
+ return dmnsn_yylex(lvalp, llocp, filename, symtable, yyscanner);
+}
diff --git a/dimension/directives.rules b/dimension/directives.rules
new file mode 100644
index 0000000..916039b
--- /dev/null
+++ b/dimension/directives.rules
@@ -0,0 +1,35 @@
+/*
+ * Start symbol
+ */
+
+LANGUAGE_DIRECTIVE: "#declare" "identifier" "=" RVALUE {
+ dmnsn_declare_symbol(symtable, $2, $4);
+ free($2);
+ dmnsn_delete_astnode($4);
+ }
+ | "#local" "identifier" "=" RVALUE {
+ dmnsn_local_symbol(symtable, $2, $4);
+ free($2);
+ dmnsn_delete_astnode($4);
+ }
+ | "#undef" "identifier" {
+ dmnsn_undef_symbol(symtable, $2);
+ free($2);
+ }
+
+RVALUE: ARITH_EXPR ";" %dprec 2 {
+ $$ = dmnsn_eval($1, symtable);
+ dmnsn_delete_astnode($1);
+
+ if ($$.type == DMNSN_AST_NONE) {
+ dmnsn_delete_astnode($$);
+ YYERROR;
+ }
+ }
+ | COLOR ";" %dprec 1
+ | OBJECT
+ | TEXTURE
+ | PIGMENT
+ | FINISH
+ | CAMERA
+ | TRANSFORMATION
diff --git a/dimension/grammar.declarations b/dimension/grammar.declarations
index c951758..247e903 100644
--- a/dimension/grammar.declarations
+++ b/dimension/grammar.declarations
@@ -17,22 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
-%define api.pure
-%locations
-%error-verbose
%token-table
%name-prefix "dmnsn_yy"
-%expect 10
-%glr-parser
+%expect 7
%parse-param {const char *filename}
%parse-param {void *yyscanner}
%parse-param {dmnsn_astree *astree}
%parse-param {dmnsn_symbol_table *symtable}
-%lex-param {const char *filename}
-%lex-param {void *yyscanner}
-
-%destructor { free($$); } <value>
-%destructor { dmnsn_delete_astnode($$); } <astnode>
diff --git a/dimension/grammar.epilogue b/dimension/grammar.epilogue
index 345fa0f..b62165e 100644
--- a/dimension/grammar.epilogue
+++ b/dimension/grammar.epilogue
@@ -34,6 +34,7 @@ dmnsn_parse(FILE *file, dmnsn_symbol_table *symtable)
dmnsn_yylex_init(&scanner);
dmnsn_yyset_in(file, scanner);
+ dmnsn_yyset_extra(NULL, scanner);
if (yyparse(filename, scanner, astree, symtable) != 0) {
dmnsn_delete_astree(astree);
diff --git a/dimension/grammar.nonterminals b/dimension/grammar.nonterminals
index ae752c3..4b608c1 100644
--- a/dimension/grammar.nonterminals
+++ b/dimension/grammar.nonterminals
@@ -20,64 +20,6 @@
/* Top-level items */
%type <astnode> SCENE_ITEM
-/* Language directives */
-%type <astnode> RVALUE
-%type <astnode> IDENTIFIER
-
-/* Transformations */
-%type <astnode> TRANSFORMATION
-
-/* The camera */
-%type <astnode> CAMERA
-%type <astnode> CAMERA_ITEMS
-%type <astnode> CAMERA_ITEM
-%type <astnode> CAMERA_TYPE
-%type <astnode> CAMERA_VECTOR
-%type <astnode> CAMERA_MODIFIER
-
/* Atmospheric effects */
%type <astnode> ATMOSPHERIC_EFFECT
%type <astnode> BACKGROUND
-
-/* Objects */
-%type <astnode> OBJECT
-%type <astnode> FINITE_SOLID_OBJECT
-%type <astnode> BOX
-%type <astnode> LIGHT_SOURCE
-%type <astnode> SPHERE
-
-/* Object modifiers */
-%type <astnode> OBJECT_MODIFIERS
-%type <astnode> OBJECT_MODIFIER
-
-/* Textures */
-%type <astnode> TEXTURE
-%type <astnode> TEXTURE_ITEMS
-
-/* Pigments */
-%type <astnode> PIGMENT
-%type <astnode> PIGMENT_TYPE
-
-/* Finishes */
-%type <astnode> FINISH
-%type <astnode> FINISH_ITEMS
-%type <astnode> REFLECTION
-%type <astnode> REFLECTION_ITEMS
-
-/* Floats */
-%type <astnode> FLOAT
-%type <astnode> FLOAT_LITERAL
-
-/* Vectors */
-%type <astnode> VECTOR
-%type <astnode> VECTOR_LITERAL
-
-/* Generalized arithmetic expressions */
-%type <astnode> ARITH_EXPR
-
-/* Colors */
-%type <astnode> COLOR
-%type <astnode> COLOR_BODY
-%type <astnode> COLOR_VECTOR
-%type <astnode> COLOR_KEYWORD_GROUP
-%type <astnode> COLOR_KEYWORD_GROUP_INIT
diff --git a/dimension/grammar.prologue b/dimension/grammar.prologue
index 7b0db1f..598f12f 100644
--- a/dimension/grammar.prologue
+++ b/dimension/grammar.prologue
@@ -17,133 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#include "parse.h"
-#include "tokenize.h"
-#include "utility.h"
-#include <stdlib.h>
-#include <stdio.h>
-
-#define YYSTYPE dmnsn_parse_item
-#define YYLTYPE dmnsn_parse_location
-
-#define YYLLOC_DEFAULT(Current, Rhs, N) \
- do { \
- if (N) { \
- (Current).first_filename = YYRHSLOC(Rhs, 1).first_filename; \
- (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
- (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
- (Current).last_filename = YYRHSLOC(Rhs, N).last_filename; \
- (Current).last_line = YYRHSLOC(Rhs, N).last_line; \
- (Current).last_column = YYRHSLOC(Rhs, N).last_column; \
- } else { \
- (Current).first_filename = (Current).last_filename = \
- YYRHSLOC(Rhs, 0).last_filename; \
- (Current).first_line = (Current).last_line = \
- YYRHSLOC(Rhs, 0).last_line; \
- (Current).first_column = (Current).last_column = \
- YYRHSLOC(Rhs, 0).last_column; \
- } \
- } while (0)
-
-/* Create a new astnode, populating filename, line, and col */
-
-static dmnsn_astnode
-dmnsn_new_astnode(dmnsn_astnode_type type, YYLTYPE lloc)
-{
- dmnsn_astnode astnode = {
- .type = type,
- .children = dmnsn_new_array(sizeof(dmnsn_astnode)),
- .ptr = NULL,
- .refcount = malloc(sizeof(unsigned int)),
- .filename = lloc.first_filename,
- .line = lloc.first_line,
- .col = lloc.first_column
- };
-
- if (!astnode.refcount) {
- dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate reference count.");
- }
- *astnode.refcount = 1;
-
- return astnode;
-}
-
-/* Semi-shallow copy */
-static void
-dmnsn_copy_children(dmnsn_astnode dest, dmnsn_astnode src)
-{
- unsigned int i;
- for (i = 0; i < dmnsn_array_size(src.children); ++i) {
- dmnsn_astnode node;
- dmnsn_array_get(src.children, i, &node);
- ++*node.refcount;
-
- if (i < dmnsn_array_size(dest.children)) {
- dmnsn_astnode clobbered;
- dmnsn_array_get(dest.children, i, &clobbered);
- dmnsn_delete_astnode(clobbered);
- }
-
- dmnsn_array_set(dest.children, i, &node);
- }
-}
-
-static dmnsn_astnode
-dmnsn_new_astnode1(dmnsn_astnode_type type, YYLTYPE lloc, dmnsn_astnode n1)
-{
- dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
- dmnsn_array_push(astnode.children, &n1);
- return astnode;
-}
-
-static dmnsn_astnode
-dmnsn_new_astnode2(dmnsn_astnode_type type, YYLTYPE lloc,
- dmnsn_astnode n1, dmnsn_astnode n2)
-{
- dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
- dmnsn_array_push(astnode.children, &n1);
- dmnsn_array_push(astnode.children, &n2);
- return astnode;
-}
-
-static dmnsn_astnode
-dmnsn_new_astnode3(dmnsn_astnode_type type, YYLTYPE lloc,
- dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3)
-{
- dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
- dmnsn_array_push(astnode.children, &n1);
- dmnsn_array_push(astnode.children, &n2);
- dmnsn_array_push(astnode.children, &n3);
- return astnode;
-}
-
-static dmnsn_astnode
-dmnsn_new_astnode4(dmnsn_astnode_type type, YYLTYPE lloc,
- dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3,
- dmnsn_astnode n4)
-{
- dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
- dmnsn_array_push(astnode.children, &n1);
- dmnsn_array_push(astnode.children, &n2);
- dmnsn_array_push(astnode.children, &n3);
- dmnsn_array_push(astnode.children, &n4);
- return astnode;
-}
-
-static dmnsn_astnode
-dmnsn_new_astnode5(dmnsn_astnode_type type, YYLTYPE lloc,
- dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3,
- dmnsn_astnode n4, dmnsn_astnode n5)
-{
- dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc);
- dmnsn_array_push(astnode.children, &n1);
- dmnsn_array_push(astnode.children, &n2);
- dmnsn_array_push(astnode.children, &n3);
- dmnsn_array_push(astnode.children, &n4);
- dmnsn_array_push(astnode.children, &n5);
- return astnode;
-}
-
void
yyerror(YYLTYPE *locp, const char *filename, void *yyscanner,
dmnsn_astree *astree, dmnsn_symbol_table *symtable, const char *str)
diff --git a/dimension/grammar.rules b/dimension/grammar.rules
index 2558485..548e769 100644
--- a/dimension/grammar.rules
+++ b/dimension/grammar.rules
@@ -17,128 +17,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
-/* Start symbol */
+/*
+ * Start symbol
+ */
SCENE: /* empty */
- | SCENE LANGUAGE_DIRECTIVE
| SCENE SCENE_ITEM {
dmnsn_array_push(astree, &$2);
}
;
-/* Language directives */
-
-LANGUAGE_DIRECTIVE: DECLARATION
-;
-
-DECLARATION: "#declare" "identifier" "=" RVALUE {
- dmnsn_declare_symbol(symtable, $2, $4);
- free($2);
- dmnsn_delete_astnode($4);
- }
- | "#local" "identifier" "=" RVALUE {
- dmnsn_local_symbol(symtable, $2, $4);
- free($2);
- dmnsn_delete_astnode($4);
- }
- | "#undef" "identifier" {
- dmnsn_undef_symbol(symtable, $2);
- free($2);
- }
-;
-
-RVALUE: ARITH_EXPR ";" %dprec 2 {
- $$ = dmnsn_eval($1, symtable);
- dmnsn_delete_astnode($1);
-
- if ($$.type == DMNSN_AST_NONE) {
- dmnsn_delete_astnode($$);
- YYERROR;
- }
- }
- | COLOR ";" %dprec 1
-;
-
-IDENTIFIER: "identifier" {
- $$ = dmnsn_new_astnode(DMNSN_AST_IDENTIFIER, @$);
- $$.ptr = $1;
- }
-;
-
/* Top-level scene item */
SCENE_ITEM: ATMOSPHERIC_EFFECT
| CAMERA
| OBJECT
;
-/* Transformations */
-
-TRANSFORMATION: "rotate" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_ROTATION, @$, $2);
- }
- | "scale" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_SCALE, @$, $2);
- }
- | "translate" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSLATION, @$, $2);
- }
-;
-
-/* Cameras */
-
-CAMERA: "camera" "{"
- CAMERA_ITEMS
- "}"
- {
- $$ = $3;
- }
-;
-
-CAMERA_ITEMS: /* empty */ {
- $$ = dmnsn_new_astnode(DMNSN_AST_CAMERA, @$);
- }
- | CAMERA_ITEMS CAMERA_ITEM {
- $$ = $1;
- dmnsn_array_push($$.children, &$2);
- }
-;
-
-CAMERA_ITEM: CAMERA_TYPE
- | CAMERA_VECTOR
- | CAMERA_MODIFIER
-;
-
-CAMERA_TYPE: "perspective" {
- $$ = dmnsn_new_astnode(DMNSN_AST_PERSPECTIVE, @$);
- }
-;
-
-CAMERA_VECTOR: "location" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_LOCATION, @$, $2);
- }
- | "right" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_RIGHT, @$, $2);
- }
- | "up" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_UP, @$, $2);
- }
- | "sky" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_SKY, @$, $2);
- }
- | "direction" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DIRECTION, @$, $2);
- }
-;
-
-CAMERA_MODIFIER: "angle" FLOAT {
- $$ = dmnsn_new_astnode1(DMNSN_AST_ANGLE, @$, $2);
- }
- | "look_at" VECTOR {
- $$ = dmnsn_new_astnode1(DMNSN_AST_LOOK_AT, @$, $2);
- }
- | TRANSFORMATION
-;
-
/* Atmospheric effects */
ATMOSPHERIC_EFFECT: BACKGROUND
@@ -148,415 +42,3 @@ BACKGROUND: "background" "{" COLOR "}" {
$$ = dmnsn_new_astnode1(DMNSN_AST_BACKGROUND, @$, $3);
}
;
-
-/* Objects */
-
-OBJECT: FINITE_SOLID_OBJECT
- | LIGHT_SOURCE
-;
-
-FINITE_SOLID_OBJECT: BOX
- | SPHERE
-;
-
-BOX: "box" "{"
- VECTOR "," VECTOR
- OBJECT_MODIFIERS
- "}"
- {
- $$ = dmnsn_new_astnode3(DMNSN_AST_BOX, @$, $3, $5, $6);
- }
-;
-
-LIGHT_SOURCE: "light_source" "{"
- VECTOR "," COLOR
- "}"
- {
- $$ = dmnsn_new_astnode2(DMNSN_AST_LIGHT_SOURCE, @$, $3, $5);
- }
-;
-
-SPHERE: "sphere" "{"
- VECTOR "," FLOAT
- OBJECT_MODIFIERS
- "}"
- {
- $$ = dmnsn_new_astnode3(DMNSN_AST_SPHERE, @$, $3, $5, $6);
- }
-;
-
-/* Object modifiers */
-
-OBJECT_MODIFIERS: /* empty */ {
- $$ = dmnsn_new_astnode(DMNSN_AST_OBJECT_MODIFIERS, @$);
- }
- | OBJECT_MODIFIERS OBJECT_MODIFIER {
- $$ = $1;
- dmnsn_array_push($$.children, &$2);
- }
-;
-
-OBJECT_MODIFIER: TRANSFORMATION
- | TEXTURE
- | PIGMENT {
- $$ = dmnsn_new_astnode1(DMNSN_AST_TEXTURE, @$, $1);
- }
-;
-
-/* Textures */
-
-TEXTURE: "texture" "{"
- TEXTURE_ITEMS
- "}"
- { $$ = $3; }
-;
-
-TEXTURE_ITEMS: /* empty */ {
- $$ = dmnsn_new_astnode(DMNSN_AST_TEXTURE, @$);
- }
- | TEXTURE_ITEMS PIGMENT {
- $$ = $1;
- dmnsn_array_push($$.children, &$2);
- }
- | TEXTURE_ITEMS FINISH {
- $$ = $1;
- dmnsn_array_push($$.children, &$2);
- }
-;
-
-/* Pigments */
-
-PIGMENT: "pigment" "{"
- PIGMENT_TYPE
- "}"
- {
- $$ = dmnsn_new_astnode1(DMNSN_AST_PIGMENT, @$, $3);
- }
-;
-
-PIGMENT_TYPE: /* empty */ {
- $$ = dmnsn_new_astnode(DMNSN_AST_NONE, @$);
- }
- | COLOR
-;
-
-/* Finishes */
-FINISH: "finish" "{"
- FINISH_ITEMS
- "}"
- { $$ = $3; }
-;
-
-FINISH_ITEMS: /* empty */ {
- $$ = dmnsn_new_astnode(DMNSN_AST_FINISH, @$);
- }
- | FINISH_ITEMS "ambient" COLOR {
- dmnsn_astnode ambient = dmnsn_new_astnode1(DMNSN_AST_AMBIENT,
- @2, $3);
- $$ = $1;
- dmnsn_array_push($$.children, &ambient);
- }
- | FINISH_ITEMS "diffuse" FLOAT {
- dmnsn_astnode diffuse = dmnsn_new_astnode1(DMNSN_AST_DIFFUSE,
- @2, $3);
- $$ = $1;
- dmnsn_array_push($$.children, &diffuse);
- }
- | FINISH_ITEMS "phong" FLOAT {
- dmnsn_astnode phong = dmnsn_new_astnode1(DMNSN_AST_PHONG, @2, $3);
- $$ = $1;
- dmnsn_array_push($$.children, &phong);
- }
- | FINISH_ITEMS "phong_size" FLOAT {
- dmnsn_astnode phong_size
- = dmnsn_new_astnode1(DMNSN_AST_PHONG_SIZE, @2, $3);
- $$ = $1;
- dmnsn_array_push($$.children, &phong_size);
- }
- | FINISH_ITEMS REFLECTION {
- $$ = $1;
- dmnsn_array_push($$.children, &$2);
- }
-;
-
-REFLECTION: "reflection" "{"
- COLOR
- REFLECTION_ITEMS
- "}"
- {
- ++*$3.refcount;
- $$ = dmnsn_new_astnode3(DMNSN_AST_REFLECTION, @$, $3, $3, $4);
- }
- | "reflection" "{"
- COLOR "," COLOR
- REFLECTION_ITEMS
- "}"
- {
- $$ = dmnsn_new_astnode3(DMNSN_AST_REFLECTION, @$, $3, $5, $6);
- }
-;
-
-REFLECTION_ITEMS: /* empty */ {
- $$ = dmnsn_new_astnode(DMNSN_AST_REFLECTION_ITEMS, @$);
- }
- | REFLECTION_ITEMS "falloff" FLOAT {
- dmnsn_astnode falloff
- = dmnsn_new_astnode1(DMNSN_AST_FALLOFF, @2, $3);
- $$ = $1;
- dmnsn_array_push($$.children, &falloff);
- }
-;
-
-/* Floats */
-
-FLOAT: ARITH_EXPR {
- $$ = dmnsn_eval_scalar($1, symtable);
- dmnsn_delete_astnode($1);
-
- if ($$.type == DMNSN_AST_NONE) {
- dmnsn_delete_astnode($$);
- YYERROR;
- }
- }
-;
-
-FLOAT_LITERAL: "integer" {
- $$ = dmnsn_new_astnode(DMNSN_AST_INTEGER, @$);
- $$.ptr = malloc(sizeof(long));
- if (!$$.ptr)
- dmnsn_error(DMNSN_SEVERITY_HIGH,
- "Failed to allocate room for integer.");
-
- *(long *)$$.ptr = strtol($1, NULL, 0);
- free($1);
- }
- | "float" {
- $$ = dmnsn_new_astnode(DMNSN_AST_FLOAT, @$);
- $$.ptr = malloc(sizeof(double));
- if (!$$.ptr)
- dmnsn_error(DMNSN_SEVERITY_HIGH,
- "Failed to allocate room for float.");
-
- *(double *)$$.ptr = strtod($1, NULL);
- free($1);
- }
-;
-
-/* Vectors */
-
-VECTOR: ARITH_EXPR {
- $$ = dmnsn_eval_vector($1, symtable);
- dmnsn_delete_astnode($1);
-
- if ($$.type == DMNSN_AST_NONE) {
- dmnsn_delete_astnode($$);
- YYERROR;
- }
- }
-;
-
-VECTOR_LITERAL: "<" ARITH_EXPR "," ARITH_EXPR ">" {
- $$ = dmnsn_new_astnode2(DMNSN_AST_VECTOR, @$, $2, $4);
- }
- | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ">" {
- $$ = dmnsn_new_astnode3(DMNSN_AST_VECTOR, @$, $2, $4, $6);
- }
- | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ","
- ARITH_EXPR ">" {
- $$ = dmnsn_new_astnode4(DMNSN_AST_VECTOR, @$, $2, $4, $6, $8);
- }
- | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ","
- ARITH_EXPR "," ARITH_EXPR ">" {
- $$ = dmnsn_new_astnode5(DMNSN_AST_VECTOR, @$,
- $2, $4, $6, $8, $10);
- }
-;
-
-/* Generalized arithmetic expressions */
-
-ARITH_EXPR: FLOAT_LITERAL
- | VECTOR_LITERAL
- | ARITH_EXPR "+" ARITH_EXPR {
- $$ = dmnsn_new_astnode2(DMNSN_AST_ADD, @$, $1, $3);
- }
- | ARITH_EXPR "-" ARITH_EXPR {
- $$ = dmnsn_new_astnode2(DMNSN_AST_SUB, @$, $1, $3);
- }
- | ARITH_EXPR "*" ARITH_EXPR {
- $$ = dmnsn_new_astnode2(DMNSN_AST_MUL, @$, $1, $3);
- }
- | ARITH_EXPR "/" ARITH_EXPR {
- $$ = dmnsn_new_astnode2(DMNSN_AST_DIV, @$, $1, $3);
- }
- | "+" ARITH_EXPR %prec DMNSN_T_NEGATE { $$ = $2; }
- | "-" ARITH_EXPR %prec DMNSN_T_NEGATE {
- $$ = dmnsn_new_astnode1(DMNSN_AST_NEGATE, @$, $2);
- }
- | ARITH_EXPR "." "x" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1);
- }
- | ARITH_EXPR "." "u" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1);
- }
- | ARITH_EXPR "." "red" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1);
- }
- | ARITH_EXPR "." "y" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1);
- }
- | ARITH_EXPR "." "v" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1);
- }
- | ARITH_EXPR "." "green" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1);
- }
- | ARITH_EXPR "." "z" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Z, @$, $1);
- }
- | ARITH_EXPR "." "blue" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Z, @$, $1);
- }
- | ARITH_EXPR "." "t" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_T, @$, $1);
- }
- | ARITH_EXPR "." "filter" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_T, @$, $1);
- }
- | ARITH_EXPR "." "transmit" {
- $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_TRANSMIT, @$, $1);
- }
- | "(" ARITH_EXPR ")" { $$ = $2; }
- | IDENTIFIER
-;
-
-/* Colors */
-
-COLOR: COLOR_BODY {
- $$ = $1;
- $$.type = DMNSN_AST_COLOR;
- }
- | "color" COLOR_BODY {
- $$ = $2;
- $$.type = DMNSN_AST_COLOR;
- }
-;
-
-COLOR_BODY: COLOR_VECTOR %dprec 1
- | COLOR_KEYWORD_GROUP %dprec 2
-;
-
-COLOR_VECTOR: "rgb" VECTOR {
- dmnsn_astnode f, t;
- dmnsn_array_get($2.children, 3, &f);
- dmnsn_array_get($2.children, 4, &t);
- dmnsn_delete_astnode(f);
- dmnsn_delete_astnode(t);
-
- dmnsn_array_resize($2.children, 3);
-
- $$ = dmnsn_eval_vector($2, symtable);
- dmnsn_delete_astnode($2);
- }
- | "rgbf" VECTOR {
- dmnsn_astnode t;
- dmnsn_array_get($2.children, 4, &t);
- dmnsn_delete_astnode(t);
-
- dmnsn_array_resize($2.children, 4);
-
- $$ = dmnsn_eval_vector($2, symtable);
- dmnsn_delete_astnode($2);
- }
- | "rgbt" VECTOR {
- /* Chop off the fifth component */
- dmnsn_astnode t;
- dmnsn_array_get($2.children, 4, &t);
- dmnsn_delete_astnode(t);
-
- dmnsn_array_resize($2.children, 4);
-
- $$ = dmnsn_eval_vector($2, symtable);
- dmnsn_delete_astnode($2);
-
- /* Swap the transmit and filter components */
- dmnsn_astnode temp;
- dmnsn_array_get($$.children, 4, &temp);
- dmnsn_array_set($$.children, 4, dmnsn_array_at($$.children, 3));
- dmnsn_array_set($$.children, 3, &temp);
- }
- | "rgbft" VECTOR { $$ = $2; }
- | VECTOR
-;
-
-COLOR_KEYWORD_GROUP: COLOR_KEYWORD_GROUP_INIT COLOR_KEYWORD_ITEM
- | COLOR_KEYWORD_GROUP COLOR_KEYWORD_ITEM
-;
-
-COLOR_KEYWORD_GROUP_INIT: /* empty */ {
- dmnsn_astnode zero =
- dmnsn_new_astnode(DMNSN_AST_INTEGER, @$);
- zero.ptr = malloc(sizeof(long));
- if (!zero.ptr)
- dmnsn_error(DMNSN_SEVERITY_HIGH,
- "Failed to allocate room for integer.");
- *(long *)zero.ptr = 0;
-
- $$ = dmnsn_eval_vector(zero, symtable);
- dmnsn_delete_astnode(zero);
- }
-;
-
-COLOR_KEYWORD_ITEM: "identifier" {
- dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, $1);
- if (!symbol) {
- dmnsn_diagnostic(@1.first_filename, @1.first_line,
- @1.first_column,
- "unbound identifier '%s'", $1);
- free($1);
- YYERROR;
- } else if (symbol->type != DMNSN_AST_COLOR) {
- dmnsn_astnode eval = dmnsn_eval_vector(*symbol, symtable);
- if (eval.type == DMNSN_AST_NONE) {
- free($1);
- YYERROR;
- }
-
- dmnsn_copy_children($<astnode>0, eval);
- dmnsn_delete_astnode(eval);
- } else {
- dmnsn_copy_children($<astnode>0, *symbol);
- }
-
- free($1);
- }
- | "red" FLOAT {
- dmnsn_astnode old;
- dmnsn_array_get($<astnode>0.children, 0, &old);
- dmnsn_array_set($<astnode>0.children, 0, &$2);
- dmnsn_delete_astnode(old);
- }
- | "green" FLOAT {
- dmnsn_astnode old;
- dmnsn_array_get($<astnode>0.children, 1, &old);
- dmnsn_array_set($<astnode>0.children, 1, &$2);
- dmnsn_delete_astnode(old);
- }
- | "blue" FLOAT {
- dmnsn_astnode old;
- dmnsn_array_get($<astnode>0.children, 2, &old);
- dmnsn_array_set($<astnode>0.children, 2, &$2);
- dmnsn_delete_astnode(old);
- }
- | "filter" FLOAT {
- dmnsn_astnode old;
- dmnsn_array_get($<astnode>0.children, 3, &old);
- dmnsn_array_set($<astnode>0.children, 3, &$2);
- dmnsn_delete_astnode(old);
- }
- | "transmit" FLOAT {
- dmnsn_astnode old;
- dmnsn_array_get($<astnode>0.children, 4, &old);
- dmnsn_array_set($<astnode>0.children, 4, &$2);
- dmnsn_delete_astnode(old);
- }
-;
diff --git a/dimension/lexer.l b/dimension/lexer.l
index e456e24..9510bcf 100644
--- a/dimension/lexer.l
+++ b/dimension/lexer.l
@@ -278,6 +278,7 @@ dmnsn_tokenize(FILE *file, const char *filename)
yylex_init(&scanner);
yyset_in(file, scanner);
+ yyset_extra(NULL, scanner);
while ((token.type = dmnsn_yylex_impl(&item, &location, filename, scanner))
!= 0) {
diff --git a/dimension/tokenize.c b/dimension/tokenize.c
index 74caace..4a9e9c6 100644
--- a/dimension/tokenize.c
+++ b/dimension/tokenize.c
@@ -18,13 +18,216 @@
*************************************************************************/
#include "tokenize.h"
+#include "directives.h"
+#include "utility.h"
+
+typedef struct dmnsn_buffered_token {
+ int type;
+ dmnsn_parse_item lval;
+ dmnsn_parse_location lloc;
+} dmnsn_buffered_token;
+
+typedef struct dmnsn_yylex_extra {
+ int type;
+ /* Indicate that the first token should be returned as-is */
+ #define DMNSN_T_LEX_VERBATIM DMNSN_T_EOF
+
+ dmnsn_array *buffered;
+ unsigned int i;
+
+ struct dmnsn_yylex_extra *prev;
+} dmnsn_yylex_extra;
+
+dmnsn_yylex_extra *
+dmnsn_new_yylex_extra(int type)
+{
+ dmnsn_yylex_extra *extra = malloc(sizeof(dmnsn_yylex_extra));
+ if (!extra) {
+ dmnsn_error(DMNSN_SEVERITY_HIGH, "Failed to allocate token buffer.");
+ }
+
+ extra->type = type;
+ extra->buffered = dmnsn_new_array(sizeof(dmnsn_buffered_token));
+ extra->i = 0;
+ extra->prev = NULL;
+ return extra;
+}
+
+void
+dmnsn_delete_yylex_extra(dmnsn_yylex_extra *extra)
+{
+ if (extra) {
+ dmnsn_delete_array(extra->buffered);
+ free(extra);
+ }
+}
int dmnsn_yylex_impl(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp,
const char *filename, void *yyscanner);
+int dmnsn_ld_yyparse(const char *filename, void *yyscanner,
+ dmnsn_symbol_table *symtable);
int
dmnsn_yylex(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp,
- const char *filename, void *yyscanner)
+ const char *filename, dmnsn_symbol_table *symtable, void *yyscanner)
{
- return dmnsn_yylex_impl(lvalp, llocp, filename, yyscanner);
+ /*
+ * So... this is kind of ugly. POV-Ray's language directives are not parsable
+ * by reasonable bison grammar, since some require skipping arbitrary amounts
+ * of tokens, or repeatedly parsing tokens. Instead, they are implemented
+ * transparently by the lexer. The lexing function calls a separate parser
+ * to handle language directives as they arrise, and returns only non-
+ * directive tokens.
+ *
+ * Ideally we'd use a push parser for the language directives, but bison
+ * doesn't support GLR push parsers.
+ */
+
+ dmnsn_yylex_extra *extra = dmnsn_yyget_extra(yyscanner);
+
+ int token;
+ while (1) {
+ if (extra) {
+ /* We are returning buffered tokens */
+ dmnsn_buffered_token buffered;
+
+ if (extra->i < dmnsn_array_size(extra->buffered)) {
+ dmnsn_array_get(extra->buffered, extra->i, &buffered);
+ token = buffered.type;
+ *lvalp = buffered.lval;
+ *llocp = buffered.lloc;
+ ++extra->i;
+
+ if (extra->type == DMNSN_T_LEX_VERBATIM && extra->i == 1) {
+ /* Don't reprocess the first token in some situations */
+ return token;
+ }
+ } else {
+ dmnsn_yyset_extra(extra->prev, yyscanner);
+ dmnsn_delete_yylex_extra(extra);
+ extra = dmnsn_yyget_extra(yyscanner);
+ continue;
+ }
+ } else {
+ token = dmnsn_yylex_impl(lvalp, llocp, filename, yyscanner);
+ }
+
+ switch (token) {
+ case DMNSN_T_DECLARE:
+ case DMNSN_T_LOCAL:
+ {
+ dmnsn_yylex_extra *ex = dmnsn_new_yylex_extra(DMNSN_T_LEX_VERBATIM);
+ ex->prev = extra;
+
+ /* Buffer the current token */
+ dmnsn_buffered_token buffered = {
+ .type = token,
+ .lval = *lvalp,
+ .lloc = *llocp
+ };
+ dmnsn_array_push(ex->buffered, &buffered);
+
+ /* Grab all the tokens belonging to the #declare/#local */
+ int bracelevel = -1;
+ while (1) {
+ /* Recursive call */
+ buffered.type = dmnsn_yylex(&buffered.lval, &buffered.lloc,
+ filename, symtable, yyscanner);
+
+ if (buffered.type == DMNSN_T_EOF) {
+ dmnsn_diagnostic(filename, buffered.lloc.first_line,
+ buffered.lloc.first_column,
+ "unexpected end-of-file");
+ dmnsn_delete_yylex_extra(ex);
+ return DMNSN_T_LEX_ERROR;
+ } else if (buffered.type == DMNSN_T_LEX_ERROR) {
+ dmnsn_delete_yylex_extra(ex);
+ return DMNSN_T_LEX_ERROR;
+ }
+
+ dmnsn_array_push(ex->buffered, &buffered);
+
+ if (buffered.type == DMNSN_T_LBRACE) {
+ if (bracelevel < 0)
+ bracelevel = 1;
+ else
+ ++bracelevel;
+ } else if (buffered.type == DMNSN_T_RBRACE) {
+ --bracelevel;
+ if (bracelevel == 0) {
+ break;
+ }
+ } else if (buffered.type == DMNSN_T_SEMICOLON) {
+ break;
+ }
+ }
+
+ /* Fake EOF */
+ buffered.type = DMNSN_T_EOF;
+ dmnsn_array_push(ex->buffered, &buffered);
+
+ dmnsn_yyset_extra(ex, yyscanner);
+ if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) {
+ dmnsn_yyset_extra(ex->prev, yyscanner);
+ dmnsn_delete_yylex_extra(ex);
+ return DMNSN_T_LEX_ERROR;
+ }
+
+ /* Restore the previous extra pointer */
+ dmnsn_yyset_extra(ex->prev, yyscanner);
+ dmnsn_delete_yylex_extra(ex);
+ break;
+ }
+
+ case DMNSN_T_UNDEF:
+ {
+ dmnsn_yylex_extra *ex = dmnsn_new_yylex_extra(DMNSN_T_LEX_VERBATIM);
+ ex->prev = extra;
+
+ /* Buffer the current token */
+ dmnsn_buffered_token buffered = {
+ .type = token,
+ .lval = *lvalp,
+ .lloc = *llocp
+ };
+ dmnsn_array_push(ex->buffered, &buffered);
+
+ /* Recursive call */
+ buffered.type = dmnsn_yylex(&buffered.lval, &buffered.lloc,
+ filename, symtable, yyscanner);
+
+ if (buffered.type == DMNSN_T_EOF) {
+ dmnsn_diagnostic(filename, buffered.lloc.first_line,
+ buffered.lloc.first_column,
+ "unexpected end-of-file");
+ dmnsn_delete_yylex_extra(ex);
+ return DMNSN_T_LEX_ERROR;
+ } else if (buffered.type == DMNSN_T_LEX_ERROR) {
+ dmnsn_delete_yylex_extra(ex);
+ return DMNSN_T_LEX_ERROR;
+ }
+ /* Buffer the next token */
+ dmnsn_array_push(ex->buffered, &buffered);
+
+ /* Fake EOF */
+ buffered.type = DMNSN_T_EOF;
+ dmnsn_array_push(ex->buffered, &buffered);
+
+ dmnsn_yyset_extra(ex, yyscanner);
+ if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) {
+ dmnsn_yyset_extra(ex->prev, yyscanner);
+ dmnsn_delete_yylex_extra(ex);
+ return DMNSN_T_LEX_ERROR;
+ }
+
+ /* Restore the previous extra pointer */
+ dmnsn_yyset_extra(ex->prev, yyscanner);
+ dmnsn_delete_yylex_extra(ex);
+ break;
+ }
+
+ default:
+ return token;
+ }
+ }
}
diff --git a/dimension/tokenize.h b/dimension/tokenize.h
index 801092a..6dafc97 100644
--- a/dimension/tokenize.h
+++ b/dimension/tokenize.h
@@ -46,14 +46,17 @@ struct dmnsn_token {
int line, col;
};
-/* Set up the scanner */
-int dmnsn_yylex_init(void **scannerp);
-void dmnsn_yyset_in(FILE *file, void *scanner);
-int dmnsn_yylex_destroy(void *scanner);
+/* Scanner manipulation */
+int dmnsn_yylex_init(void **scannerp);
+void dmnsn_yyset_in(FILE *file, void *scanner);
+int dmnsn_yylex_destroy(void *scanner);
+void *dmnsn_yyget_extra(void *scanner);
+void dmnsn_yyset_extra(void *arbitrary_data, void *scanner);
/* Actual lexer */
int dmnsn_yylex(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp,
- const char *filename, void *yyscanner);
+ const char *filename, dmnsn_symbol_table *symtable,
+ void *yyscanner);
/* For debugging - returns an array of raw tokens */
dmnsn_array *dmnsn_tokenize(FILE *file, const char *filename);