commit 41f4765afb8d8d4749b08beefb8e0636cfce51ca Author: Georg Hopp Date: Wed Dec 13 14:25:02 2006 +0000 Initial repository layout diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..ffa03c4 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Georg Steffers diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..51c863d --- /dev/null +++ b/ChangeLog @@ -0,0 +1,60 @@ +0.0.1: First test with a bison grammar and flex scanner. Process simple + statement as in the examples contained in the bison docs. +0.0.2: more work on grammar (add loops and conditionals, experiments), + also add tplparser.[ch] that serves for general purpose grammer + actions. +0.0.3: brought the grammar to a more or less final state. + Add several functions for procession different expressions. + Add variables. + Do some leak checking. +0.0.4: Finalize variables with adding support for arrays and hashes. + A word to variables: + - There is no need to declare a variable. As soon as one assigns + something to an identifier, that identifier holds that value. + - It is an error to use a variable that has no assigned value + within an expression. + - Assigning a new value to a variable simply overwrites its + previous content. There is no way to recover the previous + content. + - The above is also true if the variable was an array or hash. + - Variables can be of type INT, FLOAT or STRING. If you use + Variables or values of different type within an expression + implicit casts are done. For rules of implicit casts see below. + - There is actually no way to explicitly cast a variable, but that + may change in future. + - Rules for implicit casts are: + * normally the first operand of an expression specifies the + resulting type. All following operands are implicitly cast to + the type of the first operand. + * The only exception to this is if one of the operands is a + sting. Then all other operands are implicitly cast to string. + Again do some leak and memchecks. + +0.0.5: implement explicit casts + put all things in a sane autobuild package. + called the whole thing: tepal "TEpal is a template PArsing Library" + +0.0.6: 25/11/2006 lots of code cleanups to prepare to code to use AST + all expressions have now an own datatype. That reduces the grammar + file a lot (and makes it easier to keep it conflict-free) because + i do not need to distinguish between int, float and string in the + grammar right now. + Also expression computation has become much cleaned. + I also change the behaviour of freeing data. No function frees + any of it calling parameters. This results in a lot of + memory leaks right now. !!!IMPORTANT!!! That has to be fixed soon! + --- + Already fixed some leaks, but some still remain. + + 26/11/2006 more leaks resolved + well, right now no leaks remain when i use tepal with my test + index.html + --- + If an undefined variable is used an error message is given. + !!!FIXME!!! I need a way to maintain the complete variable identifier + to tell it with the error message. + +0.0.7: AST implemented + a very big step is done. An ast is implemented. Everything works as + before, but right now to demontrate the functionality of the ast also + if statements are computed correctly. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..07df2bf --- /dev/null +++ b/Makefile.am @@ -0,0 +1,9 @@ +DEFS = -DHAS_CONFIG @DEFS@ + +nobase_include_HEADERS = index.tpl + +ACLOCAL_AMFLAGS = -I m4 + +# EXTRA_DIST = + +SUBDIRS = src include diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..472b0c1 --- /dev/null +++ b/README @@ -0,0 +1,21 @@ +tepal is a Template Parsing Library, written in C. + +It's origin lies in my unhappieness with PHP, JSP and other +languages designed for web-development. Lately i learned a little +about template system and worked a little with smarty and after a +while i got the idea that if one wants to seperate program logic +from display logic it is also possible to write you application +in C as i prefer. The FastCGI interface is as fast or even faster than +the PHP interface. The only thing needed is a library that does the +same things as smarty, set template variables, parse a template and +write the result. + +Well, it turns out that this only thing was more work than i first +thought, especially because i never wrote an interpreter or compiler +before. And i had not college courses on that issue too. So i had to +find out everything by my own. Thanks go to the excellent documentation +of flex and bison and the Telos GmbH that published a simple interpreter. + +While i was writing this I recognised that it might be usefull at other +things too. Everything that can be created by a cleartext template +and some application logic can be created with this lib. diff --git a/TODO b/TODO new file mode 100644 index 0000000..e03f18d --- /dev/null +++ b/TODO @@ -0,0 +1,63 @@ +for version 0.0.* + +- implement blocks + * every block has to have its own identifier list. Additional + a reference to to the upper block should be part of a block + to realize variable lookup in upper blocks. + * every block contains a statement list, that hold all statements + that occured within the block. + * a block is as itself a statement, that could be part of a statement + list. + * blocklocal, global and parent variables + variables in general are block local. This means, using varable a + within a sub-block does not affect an existing variable a within a + parent block. + Every block can contain one optional globals declaration section. This + is a special block, wich declares identifiers to be used as global + (topmost block) identifiers. If a non-existent identifier is deklared + in such a section a global variable is created. + Additionally there will be a _parent_ operator for use with an identifier. + This will allow one to access a variable used (and therefor deklared) + somewhere above the local block. If no variable with this identifier can + be found an error message is shown and processing will stop. + +- implement loops and conditionals + * first the statement directly following the loop or conditional + tokens is saved. + * the this is executed 0..n times depending on the loop or conditional. + +- ich habe herausgefunden das alle Ausdrücken in denen Variablen vorkommen + auch in einen statement stack aufgenommen werden müssen. Nur konstante + Ausdrücken können direkt ausgewertet werden und muessen nicht in + den AST (abstract statement tree, ist faktisch aber eher ein stack da + jeder branch unmittelbar ausgeführt wird). Ups, sorry this is + accidently german. + +- Add an interface to access the variable space of the interpreter from + within a C program in an easy way. + +- add CGI-lib for parsing of requests. + +- write a first test-webapp. + +- code cleanups + +- comment the code more completely. + +- date Datentyp hinzufügen + +- Modifizierer für das Ausgabeformat hinzufügen. + +=> we come to version 0.1.0 +========================================================================= + +for version 0.1.* + +- implement Sessions + * How to work with cookies? + * Sessionvariables will be saves within a BerkDB. + +- maybe begin of an application-server, that preserves the state of an + application between its calls via cgi. + +- allow and implement includes within templates. diff --git a/autoclean.sh b/autoclean.sh new file mode 100755 index 0000000..8bf2b42 --- /dev/null +++ b/autoclean.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# Script for cleaning all autogenerated files. + +test ! -f Makefile || make distclean + +# Generated by aclocal. +rm -f aclocal.m4 + +# Generated by autoconf. +rm -f configure + +# Generated by autoheader +rm -f config.h.in + +# Generated or brought in by automake. +rm -f Makefile.in +rm -f src/Makefile.in +rm -f include/Makefile.in +rm -f INSTALL +rm -f COPYING + +# Generated by all in config +rm -rf config + +rm -rf autom4te.cache diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..ec37c48 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Script for regenerating all autogenerated files. + +mkdir config + +aclocal +autoconf +autoheader +libtoolize -c -f +automake -a -c diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..d9ea186 --- /dev/null +++ b/configure.ac @@ -0,0 +1,46 @@ +AC_PREREQ(2.59) +AC_INIT(tepal, 0.0.7, georg@steffers.org) +AC_CONFIG_AUX_DIR([config]) +AC_CONFIG_SRCDIR([src/tepal.c]) +AC_CONFIG_HEADER([config.h]) +AM_INIT_AUTOMAKE + +AC_CANONICAL_HOST + +# Checks for programs. +AC_PROG_CC +AC_PROG_MAKE_SET +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL +AC_PROG_YACC +AC_PROG_LEX + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([libintl.h locale.h stdlib.h string.h unistd.h wchar.h]) + +# Checks for libraries. +AC_MSG_CHECKING([for Win32]) +case "$host" in + *-*-mingw*) + win32="yes, use windows threads" + ;; + *) + win32="no" + ;; +esac +AC_MSG_RESULT([$win32]) + +AM_CONDITIONAL(WIN32, test "x$win32" != "xno") + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +# Checks for library functions. +AC_CHECK_FUNCS([memset setlocale]) + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([src/Makefile]) +AC_CONFIG_FILES([include/Makefile]) + +AC_OUTPUT diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..98c02d3 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,6 @@ +nobase_include_HEADERS = tepal.h helper.h \ + evalExpr.h evalCond.h expValue.h \ + ident.h identList.h bbtree.h \ + variable.h assign.h cast.h \ + statement.h stmtQueue.h block.h + diff --git a/include/assign.h b/include/assign.h new file mode 100644 index 0000000..2904e7a --- /dev/null +++ b/include/assign.h @@ -0,0 +1,9 @@ +#ifndef _ASSIGN_H_ +#define _ASSIGN_H_ + +#include +#include + +s_expVal * assign (s_ident *, s_expVal *); + +#endif /* _ASSIGN_H_ */ diff --git a/include/bbtree.h b/include/bbtree.h new file mode 100644 index 0000000..a1a6542 --- /dev/null +++ b/include/bbtree.h @@ -0,0 +1,66 @@ +#ifndef _BBTREE_H_ +#define _BBTREE_H_ + +/* this is only here for testing. In final version + * it should be in bbtree.c */ +typedef +struct bbTreeNode +{ + void * value; + + long height; + + struct bbTreeNode * left; + struct bbTreeNode * right; + +} s_bbTreeNode; + +#define BBTREE_LEFT_HEIGHT(t) ((t)->left ? (t)->left->height : -1) +#define BBTREE_RIGHT_HEIGHT(t) ((t)->right ? (t)->right->height : -1) +#define BBTREE_AVL(t) (BBTREE_RIGHT_HEIGHT ((t)) - \ + BBTREE_LEFT_HEIGHT ((t))) + + +/* + * comparison for tree-node values. + * Has to be defined by user and set + * with bbTreeNew. + * + * params: + * left: pointer to left value + * right: pointer to right value + * + * returns: + * 0: if values equal + * 1: if right greater left + * -1: if left greater right + */ +typedef int (* t_bbTreeCmp) (void *, void *); + +typedef +struct bbTree +{ + struct bbTreeNode * root; + + t_bbTreeCmp cmp; +} s_bbTree; + + +/* constructor, destructor */ +s_bbTree * bbTreeNew (t_bbTreeCmp); +void bbTreeFree (s_bbTree *); + +/* data manipulation */ +void * bbTreeInsert (s_bbTree *, void *); +void * bbTreeSeek (s_bbTree *, void *); +void * bbTreeRemove (s_bbTree *, void *); + +/* analysation */ +void * bbTreeMin (s_bbTree *); +void * bbTreeMax (s_bbTree *); +int bbTreeSize (s_bbTree *); + +/* bbTree to other Datastructure */ +void ** bbTreeInOrder (s_bbTree *, void **); + +#endif /* _BBTREE_H_ */ diff --git a/include/block.h b/include/block.h new file mode 100644 index 0000000..32f08d4 --- /dev/null +++ b/include/block.h @@ -0,0 +1,18 @@ +#ifndef _BLOCK_H_ +#define _BLOCK_H_ + +typedef struct block s_block; + +#include +#include + +s_block * blockNew (s_stmtQueue *); +void blockFree (s_block *); +void blockSetNonLocalId (s_block *, s_ident *); +s_block * blockPush (s_block **, s_block *); +s_block * blockPop (s_block **); +s_block * blockPrev (s_block *); +s_stmtQueue * blockStmts (s_block *); +s_identList * blockIdl (s_block *); + +#endif /* _BLOCK_H_ */ diff --git a/include/cast.h b/include/cast.h new file mode 100644 index 0000000..ab13e53 --- /dev/null +++ b/include/cast.h @@ -0,0 +1,10 @@ +#ifndef _CAST_H_ +#define _CAST_H_ + +#include "expValue.h" + +s_expVal * castExprToInt (s_expVal *); +s_expVal * castExprToFloat (s_expVal *); +s_expVal * castExprToString (s_expVal *); + +#endif /* _CAST_H_ */ diff --git a/include/evalCond.h b/include/evalCond.h new file mode 100644 index 0000000..6b748d2 --- /dev/null +++ b/include/evalCond.h @@ -0,0 +1,9 @@ +#ifndef _EVALCOND_H_ +#define _EVALCOND_H_ + +#include "expValue.h" + +int evalCondExpr (s_expVal *); +int evalComp (int, s_expVal *, s_expVal *); + +#endif /* _EVALCOND_H_ */ diff --git a/include/evalExpr.h b/include/evalExpr.h new file mode 100644 index 0000000..1b5031d --- /dev/null +++ b/include/evalExpr.h @@ -0,0 +1,15 @@ +#ifndef _EVAL_EXPR_H_ +#define _EVAL_EXPR_H_ + +#include +#include + +#define PLUS '+' +#define MINUS '-' +#define TIMES '*' +#define OVER '/' +#define MODULO '%' + +s_expVal * evalExpr (int, s_expVal *, s_expVal *); + +#endif /* _EVAL_EXPR_H_ */ diff --git a/include/expValue.h b/include/expValue.h new file mode 100644 index 0000000..92c742f --- /dev/null +++ b/include/expValue.h @@ -0,0 +1,31 @@ +#ifndef _EXP_VALUE_H_ +#define _EXP_VALUE_H_ + +#define EXP_TYP_INT 'i' +#define EXP_TYP_FLOAT 'f' +#define EXP_TYP_STRING 's' + +/* Typdeklaration, etc */ +typedef struct expVal s_expVal; + + +/* Constructoren / Destructoren */ +s_expVal * expValueIntNew (long); +s_expVal * expValueFloatNew (double); +s_expVal * expValueStringNew (char *); + +s_expVal * expValueClone (s_expVal *); + +void expValueFree (s_expVal *); + + +/* Accessors */ +long expValueInt (s_expVal *); +double expValueFloat (s_expVal *); +char * expValueString (s_expVal *); + +/* analyse expValue */ +int expValueGetType (s_expVal *); + + +#endif /* _EXP_VALUE_H_ */ diff --git a/include/helper.h b/include/helper.h new file mode 100644 index 0000000..337789e --- /dev/null +++ b/include/helper.h @@ -0,0 +1,7 @@ +#ifndef _HELPER_H_ +#define _HELPER_H_ + +#define ABS(a) ((a)<0 ? -(a) : (a)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#endif /* _HELPER_H */ diff --git a/include/ident.h b/include/ident.h new file mode 100644 index 0000000..b83bb94 --- /dev/null +++ b/include/ident.h @@ -0,0 +1,35 @@ +#ifndef _IDENT_H_ +#define _IDENT_H_ + +#define ID_TYP_UNDEF 'n' +#define ID_TYP_EXP 'e' +#define ID_TYP_IDL 'L' + +struct ident; +typedef struct ident s_ident; + +#include +#include + +/* identifier constructors/destructors */ +s_ident * identNew (int, const char *); +s_ident * identUndefNew (int, const char *); +s_ident * identExpNew (int, const char *, s_expVal *); +s_ident * identIdlNew (int, const char *, s_identList *); +void identFree (s_ident *); + +/* analyse ident */ +int identIsQueued (s_ident *); +void identEnqueue (s_ident *); +void identDequeue (s_ident *); +int identGetType (s_ident *); +char * identGetKey (s_ident *); +int identGetIdx (s_ident *); + +/* identifier to value */ +s_expVal * identExp (s_ident *); +s_identList * identIdl (s_ident *); +s_ident * identSetExp (s_ident *, s_expVal *); +s_ident * identSetIdl (s_ident *, s_identList *); + +#endif /* _IDENT_H_ */ diff --git a/include/identList.h b/include/identList.h new file mode 100644 index 0000000..b2d0702 --- /dev/null +++ b/include/identList.h @@ -0,0 +1,29 @@ +#ifndef _IDENT_LIST_H_ +#define _IDENT_LIST_H_ + +typedef struct identList s_identList; + +#include +#include + +/* constructor/destructor for new identList */ +s_identList * identListNew (void); +void identListFree (s_identList *); + +/* insertions or deletion into a list */ +s_ident * identListPutVal (s_identList *, s_ident *); +s_ident * identListPutExpByIdx (s_identList *, int, s_expVal *); +s_ident * identListPutIdlByIdx (s_identList *, int, s_identList *); +s_ident * identListPutExpByKey (s_identList *, const char *, s_expVal *); +s_ident * identListPutIdlByKey (s_identList *, const char *, s_identList *); +void identListRemoveByIdx (s_identList *, int); +void identListRemoveByKey (s_identList *, const char *); + +/* seeking in list */ +s_ident * identListSeekIdx (s_identList *, int); +s_ident * identListSeekKey (s_identList *, const char *); + +/* identList to other DataStructures */ +s_ident ** identListToArray (s_identList *); + +#endif /* _IDENT_LIST_H_ */ diff --git a/include/statement.h b/include/statement.h new file mode 100644 index 0000000..f7ad656 --- /dev/null +++ b/include/statement.h @@ -0,0 +1,74 @@ +#ifndef _STMT_H_ +#define _STMT_H_ + +#define STMT_CONST 0 +#define STMT_BLOCK 1 + +#define STMT_PRINT 10 +#define STMT_IF 11 +#define STMT_FOREACH 12 +#define STMT_REPEAT 13 +#define STMT_ASSIGN 14 +#define STMT_UNSET 15 + +#define STMT_EVAL_PLUS 20 +#define STMT_EVAL_MINUS 21 +#define STMT_EVAL_TIMES 22 +#define STMT_EVAL_OVER 23 +#define STMT_EVAL_MODULO 24 +#define STMT_EVAL_NEG 25 + +#define STMT_IDENT_VAR 30 +#define STMT_IDENT_ARRAY 31 +#define STMT_IDENT_VAL 32 + +#define STMT_CAST_INT 40 +#define STMT_CAST_FLOAT 41 +#define STMT_CAST_STRING 42 + +#define STMT_COMP_EQ 50 +#define STMT_COMP_NE 51 +#define STMT_COMP_LT 52 +#define STMT_COMP_GT 53 +#define STMT_COMP_LE 54 +#define STMT_COMP_GE 55 + +#define STMT_COND_EXPR 60 +#define STMT_COND_AND 61 +#define STMT_COND_OR 62 +#define STMT_COND_NEG 63 + + + +#define STYP_NONE 0 +#define STYP_COND 1 +#define STYP_EVAL 2 +#define STYP_IDVAL 3 + +/* + * Deklaration und Definition + */ +union stmtType +{ + int cond; + struct expVal * eVal; + struct ident * idVal; +}; + +typedef struct stmt s_stmt; +typedef union stmtType u_stmtType; + +#include +#include + +/* + * Interface + */ +s_stmt * stmtNew (int, s_stmtQueue *, int, u_stmtType); +void stmtFree (s_stmt *); +s_stmtQueue * stmtGetArgs (s_stmt *); +u_stmtType stmtGetVal (s_stmt *); +int stmtGetConstTyp (s_stmt *); +u_stmtType stmtDo (s_stmt *, s_block *); + +#endif /* _STMT_H_ */ diff --git a/include/stmtQueue.h b/include/stmtQueue.h new file mode 100644 index 0000000..f0c07de --- /dev/null +++ b/include/stmtQueue.h @@ -0,0 +1,22 @@ +#ifndef _STMT_QUEUE_H_ +#define _STMT_QUEUE_H_ + +#include + +typedef struct stmtQueue s_stmtQueue; + +#include + +s_stmtQueue * stmtQueueNew (void); +void stmtQueueFree (s_stmtQueue *); + +void stmtQueueEnqueue (s_stmtQueue *, s_stmt *); +s_stmt * stmtQueueDequeue (s_stmtQueue *); +s_stmtQueue * stmtQueueConcat (s_stmtQueue *, s_stmtQueue *); + +s_stmt * stmtQueueGet (s_stmtQueue *, unsigned int); +void stmtQueueDo (s_stmtQueue *); + +unsigned int stmtQueueGetSize (s_stmtQueue *); + +#endif /* _STMT_QUEUE_H_ */ diff --git a/include/tepal.h b/include/tepal.h new file mode 100644 index 0000000..df29302 --- /dev/null +++ b/include/tepal.h @@ -0,0 +1,14 @@ +#ifndef __HTMLPARS_H__ +#define __HTMLPARS_H__ + +#include "expValue.h" + +#define ERR_UNDEF_VAR 0 +#define ERR_NO_INDEX 1 +#define ERR_STRING_OPERATOR 2 +#define ERR_FLOAT_OPERATOR 3 + +void exitError (int, ...); +void printExpr (s_expVal *); + +#endif /* __HTMLPARS_H__ */ diff --git a/include/variable.h b/include/variable.h new file mode 100644 index 0000000..c5ef74a --- /dev/null +++ b/include/variable.h @@ -0,0 +1,11 @@ +#ifndef _VARIABLE_H_ +#define _VARIABLE_H_ + +#include +#include +#include + +s_ident * getVariable (s_block *, char *); +s_ident * getArray (s_ident *, s_expVal *); + +#endif /* _VARIABLE_H_ */ diff --git a/index.tpl b/index.tpl new file mode 100644 index 0000000..4f20787 --- /dev/null +++ b/index.tpl @@ -0,0 +1,101 @@ + + + + Test Page for Apache Installation + + + +

If you can see this, it means that the installation of the Apache web server + software on this system was successful. You may now add content to this + directory and replace this page.

+ +
+ +

Seeing this instead of the website you expected?

+ + <# "[Ausdruck 5 + 5] " + (5 + 5) + eol #> + + <# if (! 'HALLO' == 'HALLO'): #> +

This page is here because the site administrator has changed the + configuration of this web server. Please contact the person + responsible for maintaining this server with questions. + The Apache Software Foundation, which wrote the web server software + this site administrator is using, has nothing to do with + maintaining this site and cannot help resolve configuration + issues.

+ <# end #> + + <# + if (! (12 < 13 && 12 < 10)) + + : + "[Zuweisung yahoo = 15] " + eol; yahoo = 15; + "[Ausdruck yahoo] " + yahoo + eol; + + end + + "[Ausdruck 10 % 3] " + (10 % 3) + eol;;;; + "[Ausdruck 12.3 - 18] " + (12.3 - 18) + eol; + "[Ausdruck -47.78] " + -47.78 + eol; + "[Ausdruck 'HALLO'] " + 'HALLO' + eol; + '[Ausdruck -"WALLO"] ' + -"WALLO" + eol; + "[Ausdruck 'hokus ' + 'pokus'] " + ('hokus ' + 'pokus') + eol; + + repeat (bla count=10) + "[Ausdruck 32.56 * 10] " + 32.56 * 10 + eol; + + "[Zuweisung a = 250]" + eol; a = 250; + "[Zuweisung b=3.4-0.9]" + eol; b=3.4-0.9; + '[Zuweisung z="bla" + "bla"]' + eol; z="bla" + "bla"; + + "[Ausdruck a] " + a + eol; + "[Ausdruck a*10 + a*2] " + (a*10 + a*2) + eol; + + "[Zuweisung a = -'Georg']" + eol; a = -'Georg'; + "[Ausdruck -a] " + -a + eol; + "[Ausdruck a] " + a + eol; + + if (a == b) + "[Ausdruck 152 - 38] " + (152 - 38) + eol; + else + "[Ausdruck 'Harry' + -'hcsriH'] " + 'Harry' + -'hcsriH' + eol; + + foreach (harry as key, val): end + + "[Zuweisung jo ['terror'][12] = 53] " + eol; jo ['terror'][12] = 53; + "[Zuweisung onken = 'Falada']" + eol; onken = 'Falada'; + "[Ausdruck onken + jo ['terror'][12]] " + (onken + jo['terror'][12]) + eol; + "[Zuweisung toll[42] = 'Jedi']" + eol; toll[42] = 'Jedi'; + "[Ausdruck -toll[42]] " + -toll[42] + eol; + + "[Zuweisung harry = 12.0]" + eol; harry = 12.0; + "[Ausdruck harry*32] " + (harry*32) + eol; + "[Zuweisung dieter = 0]" + eol; dieter = 0; + "[Ausdruck 12.4+dieter] " + (12.4+dieter) + eol; + "[Zuweisung bonbon = 0.12]" + eol; bonbon = 0.12; + '[Ausdruck "Knall"+bonbon] ' + "Knall"+bonbon + eol; + "[Zuweisung mann = 'Mann']" + eol; mann = 'Mann'; + "[Zuweisung oh = '-o-']" + eol; oh = '-o-'; + "[Ausdruck mann+oh+mann] " + (mann+oh+mann) + eol; + '[Ausdruck 13 + "5"] ' + (13 + "5") + eol; + '[Ausdruck "Hallo" + 12] ' + ("Hallo" + 12) + eol; + '[Ausdruck b + (int) "32"] ' + (b + (int) "32") + eol; + #> + +
+ + <# repeat (hoho count=100) #> +

The Apache documentation is available + online or has been installed + locally.

+ + <# foreach (jokus as key, val): #> +

You are free to use the image below on an Apache-powered web + server. Thanks for using Apache!

+ <# end #> + +
+ + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..17df80c --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,25 @@ +tepal_source = tepal.c tepal_pars.c tepal_scan.c \ + evalExpr.c evalCond.c expValue.c \ + variable.c assign.c cast.c \ + ident.c identList.c bbtree.c \ + statement.c stmtQueue.c block.c + +nobase_include_HEADERS = tepal_pars.y tepal_scan.l + +BUILT_SOURCES = tepal_pars.c tepal_scan.c +CLEANFILES = tepal_pars.c tepal_scan.c ../include/tepal_pars.h + + +bin_PROGRAMS = tepal + +tepal_SOURCES = $(tepal_source) +tepal_CFLAGS = -I../include + +tepal_pars.c: Makefile tepal_pars.y + $(YACC) -d tepal_pars.y + mv y.tab.c tepal_pars.c + mv y.tab.h ../include/tepal_pars.h + +tepal_scan.c: Makefile tepal_scan.l + $(LEX) tepal_scan.l + mv lex.yy.c tepal_scan.c diff --git a/src/assign.c b/src/assign.c new file mode 100644 index 0000000..6f8a4ce --- /dev/null +++ b/src/assign.c @@ -0,0 +1,24 @@ +#include +#include +#include + +#include +#include +#include +#include + + s_expVal * +assign (s_ident * to, s_expVal * from) +{ + if (identGetType (to) == ID_TYP_IDL) + { + char * key = identGetKey (to); + exitError (ERR_NO_INDEX, key); + } + + /* !!!IMPORTANT!!! work here */ + /*identListPutVal (block, to);*/ + identSetExp (to, from); + + return from; +} diff --git a/src/bbtree.c b/src/bbtree.c new file mode 100644 index 0000000..e22dd23 --- /dev/null +++ b/src/bbtree.c @@ -0,0 +1,411 @@ +/* + * bbTree (balanced binary tree) + */ +#include +#include +#include + +#include +#include + + +/* + * statisch Funktionen + */ +static + s_bbTreeNode * +bbTreeNodeNew (void * value) +{ + s_bbTreeNode * new = (s_bbTreeNode *) malloc (sizeof (s_bbTreeNode)); + + new->value = value; + new->left = NULL; + new->right = NULL; + new->height = 0; + + return new; +} + +static + void +bbTreeNodeFree (s_bbTreeNode * t) +{ + if (t == NULL) + return; + + while (t->left != NULL) + { + bbTreeNodeFree (t->left); + t->left = NULL; + } + + while (t->right != NULL) + { + bbTreeNodeFree (t->right); + t->right = NULL; + } + + free (t); +} + +static + void +bbTreeNodeRotLeft (s_bbTreeNode * node) +{ + s_bbTreeNode * left = node->left; + s_bbTreeNode * right = node->right; + void * value = node->value; + + node->right = right->right; + node->left = right; + right->right = right->left; + right->left = left; + + node->value = right->value; + right->value = value; + + node->right->height = + 1 + MAX (BBTREE_LEFT_HEIGHT (node->left), + BBTREE_RIGHT_HEIGHT (node->left)); +} + +static + void +bbTreeNodeRotRight (s_bbTreeNode * node) +{ + s_bbTreeNode * left = node->left; + s_bbTreeNode * right = node->right; + void * value = node->value; + + node->left = left->left; + node->right = left; + left->left = left->right; + left->right = right; + + node->value = left->value; + left->value = value; + + node->right->height = + 1 + MAX (BBTREE_LEFT_HEIGHT (node->right), + BBTREE_RIGHT_HEIGHT (node->right)); +} + +static + void +bbTreeNodeBalance (s_bbTreeNode * node) +{ + if (BBTREE_AVL (node) == -2) + /* left is to long */ + { + if (BBTREE_AVL (node->left) == 1) + bbTreeNodeRotLeft (node->left); + bbTreeNodeRotRight (node); + } + + if (BBTREE_AVL (node) == -2) + /* right is to long */ + { + if (BBTREE_AVL (node->right) == 1) + bbTreeNodeRotRight (node->right); + bbTreeNodeRotLeft (node); + } +} + +/* + * This function returns either, NULL if a new node was inserted, or + * a node containing the old value if an existing node was modified. + */ +static + s_bbTreeNode * +bbTreeNodeInsert (s_bbTreeNode ** _node, t_bbTreeCmp cmp, void * value) +{ + s_bbTreeNode * node = *_node; + s_bbTreeNode * ret; + + if (node == NULL) + /* This happens only when bbTree::root is NULL + * on bbTreeInsert call */ + { + *_node = bbTreeNodeNew (value); + return NULL; + } + + if (cmp (value, node->value) == 0) + /* The key is already in the tree. + * In this case a node containing the old value is returned. */ + { + ret = bbTreeNodeNew (node->value); + node->value = value; + return ret; + } + + if (cmp (value, node->value) < 0) + if (node->left == NULL) + { + node->left = bbTreeNodeNew (value); + ret = NULL; + + if (BBTREE_AVL (node) == -2 || BBTREE_AVL (node) == 2) + bbTreeNodeBalance (node); + + node->height = 1 + MAX ( + BBTREE_LEFT_HEIGHT (node), BBTREE_RIGHT_HEIGHT (node)); + } + else + ret = bbTreeNodeInsert (&node->left, cmp, value); + + if (cmp (value, node->value) > 0) + if (node->right == NULL) + { + node->right = bbTreeNodeNew (value); + ret = NULL; + + if (BBTREE_AVL (node) == -2 || BBTREE_AVL (node) == 2) + bbTreeNodeBalance (node); + + node->height = 1 + MAX ( + BBTREE_LEFT_HEIGHT (node), BBTREE_RIGHT_HEIGHT (node)); + } + else + ret = bbTreeNodeInsert (&node->right, cmp, value); + + /* if we come here a new node was inserted a returned node + * containing {NULL, NULL} as value reflects this fact. */ + return ret; +} + +static + s_bbTreeNode * +bbTreeNodeSeek (s_bbTreeNode * node, t_bbTreeCmp cmp, void * value) +{ + if (node == NULL) + return NULL; + + if (cmp (value, node->value) == 0) + return node; + + if (cmp (value, node->value) < 0) + return bbTreeNodeSeek (node->left, cmp, value); + + if (cmp (value, node->value) > 0) + return bbTreeNodeSeek (node->right, cmp, value); + + return NULL; +} + +static + s_bbTreeNode * +bbTreeNodeMax (s_bbTreeNode * node) +{ + if (node != NULL && node->right != NULL) + return bbTreeNodeMax (node->right); + + return node; +} + +static + s_bbTreeNode * +bbTreeNodeMin (s_bbTreeNode * node) +{ + if (node != NULL && node->left != NULL) + return bbTreeNodeMin (node->left); + + return node; +} + +static + int +bbTreeNodeSize (s_bbTreeNode * node) +{ + int size = 0; + + if (node == NULL) + return 0; + + size += bbTreeNodeSize (node->left); + size += bbTreeNodeSize (node->right); + + return size + 1; +} +/* + * This functions removes nodes from the tree and returns a pointer + * to the removed node or NULL if no node was found. + * !!!FIXME!!!: This function isn't thread save because of the static + * valiables. Don't use with multiple threads. + */ +static + s_bbTreeNode * +bbTreeNodeRemove (s_bbTreeNode ** _node, t_bbTreeCmp cmp, void * value) +{ + s_bbTreeNode * ret = NULL; + s_bbTreeNode * node = *_node; + + if (node == NULL) + return NULL; + + if (cmp (value, node->value) == 0) + /* found the element left */ + { + if (node->left == NULL && node->right == NULL) + /* found a leaf */ + { + ret = bbTreeNodeNew (node->value); + free (node); + *_node = NULL; + } + else if (node->left != NULL && node->left != NULL) + /* left & right subtree exists use either max(left) or min(right) */ + { + s_bbTreeNode * maxLeft; + + maxLeft = bbTreeNodeMax (node->left); + node->value = maxLeft->value; + ret = bbTreeNodeRemove (&node->left, cmp, maxLeft->value); + + if (BBTREE_AVL (node) == -2 || BBTREE_AVL (node) == 2) + bbTreeNodeBalance (node); + + node->height = 1 + MAX ( + BBTREE_LEFT_HEIGHT (node), BBTREE_RIGHT_HEIGHT (node)); + } + else if ((node->left == NULL) != (node->right == NULL) /* ^^ */) + /* there is only one subtree */ + /* This subtree must be a leaf, because the tree is balanced */ + { + ret = bbTreeNodeNew (node->value); + + if (node->left != NULL) + /* found left node */ + { + node->value = node->left->value; + free (node->left); + node->left = NULL; + } + else + /* found right node */ + { + node->value = node->right->value; + free (node->right); + node->right = NULL; + } + } + + return ret; + } + + if (cmp (value, node->value) < 0) + ret = bbTreeNodeRemove (&node->left, cmp, value); + + if (cmp (value, node->value) > 0) + ret = bbTreeNodeRemove (&node->right, cmp, value); + + return ret; +} + +static + void +bbTreeNodeInOrder (const s_bbTreeNode * node, void *** ret) +{ + if (node != NULL && node->left != NULL) + bbTreeNodeInOrder (node->left, ret); + + if (node != NULL) + **ret = node->value; (*ret)++; + + if (node != NULL && node->right != NULL) + bbTreeNodeInOrder (node->right, ret); +} + +/* + * Interface (non-static functions) + */ + s_bbTree * +bbTreeNew (t_bbTreeCmp cmp) +{ + s_bbTree * new = (s_bbTree *) malloc (sizeof (s_bbTree)); + + new->root = NULL; + new->cmp = cmp; + + return new; +} + + void +bbTreeFree (s_bbTree * t) +{ + bbTreeNodeFree (t->root); + + free (t); +} + + void * +bbTreeInsert (s_bbTree * t, void * value) +{ + s_bbTreeNode * oldNode = bbTreeNodeInsert (&t->root, t->cmp, value); + + if (oldNode != NULL) + { + value = oldNode->value; + free (oldNode); + + return value; + } + + return NULL; +} + + void * +bbTreeSeek (s_bbTree * t, void * value) +{ + s_bbTreeNode * seek = bbTreeNodeSeek (t->root, t->cmp, value); + + return (seek != NULL) ? seek->value : NULL; +} + + void * +bbTreeRemove (s_bbTree * t, void * value) +{ + s_bbTreeNode * oldNode = bbTreeNodeRemove (&t->root, t->cmp, value); + + if (oldNode != NULL) + { + value = oldNode->value; + free (oldNode); + + return value; + } + + return NULL; +} + + void * +bbTreeMax (s_bbTree * t) +{ + s_bbTreeNode * max = bbTreeNodeMax (t->root); + + return max == NULL ? max : max->value; +} + + void * +bbTreeMin (s_bbTree * t) +{ + s_bbTreeNode * max = bbTreeNodeMin (t->root); + + return max == NULL ? max : max->value; +} + + int +bbTreeSize (s_bbTree * t) +{ + return bbTreeNodeSize (t->root); +} + + void ** +bbTreeInOrder (s_bbTree * t, void ** buffer) +{ + void ** tmp = buffer; + + bbTreeNodeInOrder (t->root, &tmp); + + return buffer; +} diff --git a/src/block.c b/src/block.c new file mode 100644 index 0000000..38777dd --- /dev/null +++ b/src/block.c @@ -0,0 +1,82 @@ +#include +#include + +typedef struct block s_block; + +struct block /* a stack of used blocks. */ +{ + s_stmtQueue * stmts; + s_identList * idl; + + s_block * prev; +}; + + + s_block * +blockNew (s_stmtQueue * stmts) +{ + s_block * new = (s_block *) malloc (sizeof (s_block)); + + new->stmts = stmts; + new->prev = NULL; + new->idl = identListNew (new); + + return new; +} + + void +blockFree (s_block * bs) +{ + if (bs->prev != NULL) + blockFree (bs->prev); + + if (bs->stmts != NULL) + stmtQueueFree (bs->stmts); + + identListFree (bs->idl); + + free (bs); +} + + void +blockSetNonLocalId (s_block * bs, s_ident * id) +{ + s_identListPutVal (bs->idl, id); +} + + s_block * +blockPush (s_block ** bs, s_block * new) +{ + new->prev = *bs; + + *bs = new; + + return *bs; +} + + s_block * +blockPop (s_block ** bs) +{ + s_block * ret = *bs; + *bs = (*bs)->prev; + + return ret; +} + + s_block * +blockPrev (s_block * bs) +{ + return bs->prev; +} + + s_stmtQueue * +blockStmts (s_block * bs) +{ + return bs->stmts; +} + + s_identList * +blockIdl (s_block * bs) +{ + return bs->idl; +} diff --git a/src/cast.c b/src/cast.c new file mode 100644 index 0000000..7b94b2c --- /dev/null +++ b/src/cast.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +#include +#include + + s_expVal * +castExprToInt (s_expVal * eVal) +{ + return expValueIntNew (expValueInt (eVal)); +} + + s_expVal * +castExprToFloat (s_expVal * eVal) +{ + return expValueFloatNew (expValueFloat (eVal)); +} + + s_expVal * +castExprToString (s_expVal * eVal) +{ + char * val = expValueString (eVal); + s_expVal * ret = expValueStringNew (val); + + free (val); + + return ret; +} diff --git a/src/evalCond.c b/src/evalCond.c new file mode 100644 index 0000000..7b174b0 --- /dev/null +++ b/src/evalCond.c @@ -0,0 +1,113 @@ +#include +#include +#include + +#include +#include +#include + + +/* + * static function (internal only) + */ +static + int +evalIntComp (int op, s_expVal * _op1, s_expVal * _op2) +{ + long op1 = expValueInt (_op1); + long op2 = expValueInt (_op2); + + switch (op) + { + case EQ: return (op1 == op2); + case NE: return (op1 != op2); + case LT: return (op1 < op2); + case GT: return (op1 > op2); + case LE: return (op1 <= op2); + case GE: return (op1 >= op2); + } +} + +static + int +evalFloatComp (int op, s_expVal * _op1, s_expVal * _op2) +{ + double op1 = expValueFloat (_op1); + double op2 = expValueFloat (_op2); + + switch (op) + { + case EQ: return (op1 == op2); + case NE: return (op1 != op2); + case LT: return (op1 < op2); + case GT: return (op1 > op2); + case LE: return (op1 <= op2); + case GE: return (op1 >= op2); + } +} + +static + int +evalStringComp (int op, s_expVal * _op1, s_expVal * _op2) +{ + char * op1 = expValueString (_op1); + char * op2 = expValueString (_op2); + long ret; + + switch (op) + { + case EQ: ret = (! strcmp (op1, op2)); + case NE: ret = strcmp (op1, op2); + case LT: ret = (strcmp (op1, op2) < 0) ? 1 : 0; + case GT: ret = (strcmp (op1, op2) > 0) ? 1 : 0; + case LE: ret = (strcmp (op1, op2) <= 0) ? 1 : 0; + case GE: ret = (strcmp (op1, op2) >= 0) ? 1 : 0; + } + + free (op1); + free (op2); + + return ret; +} + + + +/* + * public functions (interface) + */ + int +evalCondExpr (s_expVal * _op) +{ + switch (expValueGetType (_op)) + { + case EXP_TYP_INT: return expValueInt (_op); + case EXP_TYP_FLOAT: return expValueInt (_op); + case EXP_TYP_STRING: + { + char * op = expValueString (_op); + long ret = strlen (op); + + free (op); + + return ret; + } + } + + return 0; +} + + int +evalComp (int op, s_expVal * op1, s_expVal * op2) +{ + switch (expValueGetType (op1)) + { + case EXP_TYP_INT: + return evalIntComp (op, op1, op2); + + case EXP_TYP_FLOAT: + return evalFloatComp (op, op1, op2); + + case EXP_TYP_STRING: + return evalStringComp (op, op1, op2); + } +} diff --git a/src/evalExpr.c b/src/evalExpr.c new file mode 100644 index 0000000..07391f3 --- /dev/null +++ b/src/evalExpr.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + * static function (internal only) + */ +static +inline + s_expVal * +stringPlus (s_expVal * _op1, s_expVal * _op2) +{ + s_expVal * ret; + char * op1 = expValueString (_op1); + char * op2 = expValueString (_op2); + char * retVal = (char *) malloc ( + sizeof (char) * (strlen (op1) + strlen (op2) + 1)); + + strcpy (retVal, op1); + strcat (retVal, op2); + ret = expValueStringNew (retVal); + + free (retVal); + free (op2); + free (op1); + + return ret; +} + +static +inline + s_expVal * +stringNeg (s_expVal * _op) +{ + s_expVal * ret; + int i; + + char * op = expValueString (_op); + int len = strlen (op) - 1; + + for (i=0; i<=(len/2); i++) + { + char tmp = op[i]; + op[i] = op[len-i]; + op[len-i] = tmp; + } + + ret = expValueStringNew (op); + free (op); + return ret; +} + +static +inline + s_expVal * +evalIntExp (int op, s_expVal * _op1, s_expVal * _op2) +{ + long op1 = expValueInt (_op1); + long op2 = (_op2 != NULL) ? expValueInt (_op2) : 0; + + if (op == NEG) return expValueIntNew (- op1); + + switch (expValueGetType (_op2)) + { + case EXP_TYP_INT: + case EXP_TYP_FLOAT: + switch (op) + { + case PLUS: return expValueIntNew (op1 + op2); + case MINUS: return expValueIntNew (op1 - op2); + case TIMES: return expValueIntNew (op1 * op2); + case OVER: return expValueIntNew (op1 / op2); + case MODULO: return expValueIntNew (op1 % op2); + } + + case EXP_TYP_STRING: + if (op == PLUS) + return stringPlus (_op1, _op2); + exitError (ERR_STRING_OPERATOR, op); + } +} + +static +inline + s_expVal * +evalFloatExp (int op, s_expVal * _op1, s_expVal * _op2) +{ + double op1 = expValueFloat (_op1); + double op2 = (_op2 != NULL) ? expValueFloat (_op2) : 0.0; + + if (op == NEG) return expValueFloatNew (- op1); + + switch (expValueGetType (_op2)) + { + case EXP_TYP_INT: + case EXP_TYP_FLOAT: + switch (op) + { + case MODULO: exitError (ERR_FLOAT_OPERATOR, op); + case PLUS: return expValueFloatNew (op1 + op2); + case MINUS: return expValueFloatNew (op1 - op2); + case TIMES: return expValueFloatNew (op1 * op2); + case OVER: return expValueFloatNew (op1 / op2); + } + + case EXP_TYP_STRING: + if (op == PLUS) + return stringPlus (_op1, _op2); + exitError (ERR_STRING_OPERATOR, op); + } +} + + + +/* + * public functions (interface) + */ + s_expVal * +evalExpr (int op, s_expVal * op1, s_expVal * op2) +{ + switch (expValueGetType (op1)) + { + case EXP_TYP_INT: + return evalIntExp (op, op1, op2); + + case EXP_TYP_FLOAT: + if (op != MODULO) + return evalFloatExp (op, op1, op2); + exitError (ERR_FLOAT_OPERATOR, op); + + case EXP_TYP_STRING: + if (op == PLUS) + return stringPlus (op1, op2); + if (op == NEG) + return stringNeg (op1); + exitError (ERR_STRING_OPERATOR, op); + } +} diff --git a/src/expValue.c b/src/expValue.c new file mode 100644 index 0000000..1d5ebf2 --- /dev/null +++ b/src/expValue.c @@ -0,0 +1,150 @@ +#include +#include +#include + +#include + +union expType +{ + long iVal; + double fVal; + char * cPtr; +}; + +struct expVal +{ + int type; + + union expType val; +}; + +/* + * Constructoren / Destructoren + */ + s_expVal * +expValueIntNew (long val) +{ + s_expVal * ret = (s_expVal *) malloc (sizeof (s_expVal)); + + ret->type = EXP_TYP_INT; + ret->val.iVal = val; + + return ret; +} + + s_expVal * +expValueFloatNew (double val) +{ + s_expVal * ret = (s_expVal *) malloc (sizeof (s_expVal)); + + ret->type = EXP_TYP_FLOAT; + ret->val.fVal = val; + + return ret; +} + + s_expVal * +expValueStringNew (char * val) +{ + s_expVal * ret = (s_expVal *) malloc (sizeof (s_expVal)); + + ret->type = EXP_TYP_STRING; + ret->val.cPtr = (char *) malloc (sizeof (char) * (strlen (val) + 1)); + strcpy (ret->val.cPtr, val); + + return ret; +} + + s_expVal * +expValueClone (s_expVal * eVal) +{ + s_expVal * ret = (s_expVal *) malloc (sizeof (s_expVal)); + + ret->type = eVal->type; + + switch (eVal->type) + { + case EXP_TYP_INT: ret->val.iVal = eVal->val.iVal; break; + case EXP_TYP_FLOAT: ret->val.fVal = eVal->val.fVal; break; + case EXP_TYP_STRING: + { + ret->val.cPtr = (char *) malloc ( + sizeof (char) * (strlen (eVal->val.cPtr) + 1)); + strcpy (ret->val.cPtr, eVal->val.cPtr); + } + } + + return ret; +} + + void +expValueFree (s_expVal * eVal) +{ + if (eVal->type == EXP_TYP_STRING) + free (eVal->val.cPtr); + free (eVal); +} + + +/* + * Accessors + */ + long +expValueInt (s_expVal * eVal) +{ + switch (eVal->type) + { + case EXP_TYP_INT: return eVal->val.iVal; + case EXP_TYP_FLOAT: return (long) eVal->val.fVal; + case EXP_TYP_STRING: return atoi (eVal->val.cPtr); + } +} + + double +expValueFloat (s_expVal * eVal) +{ + switch (eVal->type) + { + case EXP_TYP_INT: return (double) eVal->val.iVal; + case EXP_TYP_FLOAT: return eVal->val.fVal; + case EXP_TYP_STRING: return atof (eVal->val.cPtr); + } +} + + char * +expValueString (s_expVal * eVal) +{ + char buf[40]; + char * ret = NULL; + + switch (eVal->type) + { + case EXP_TYP_INT: + sprintf (buf, "%d", eVal->val.iVal); + ret = (char *) malloc (sizeof (char) * (strlen (buf) + 1)); + strcpy (ret, buf); + break; + + case EXP_TYP_FLOAT: + sprintf (buf, "%f", eVal->val.fVal); + ret = (char *) malloc (sizeof (char) * (strlen (buf) + 1)); + strcpy (ret, buf); + break; + + case EXP_TYP_STRING: + ret = (char *) malloc (sizeof (char) * (strlen (eVal->val.cPtr) + 1)); + strcpy (ret, eVal->val.cPtr); + break; + } + + return ret; +} + +/* + * analyse expValue + */ + int +expValueGetType (s_expVal * eVal) +{ + return eVal->type; +} diff --git a/src/ident.c b/src/ident.c new file mode 100644 index 0000000..0287a64 --- /dev/null +++ b/src/ident.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + * Typdeklaration, etc + */ +union identTypes +{ + s_expVal * base; + s_identList * idl; +}; + +struct ident +{ + char * key; + int idx; + + int queued; + + union identTypes val; +}; + + +/* + * statische Funktionen (interner gebrauch) + */ + +/* + * nicht statische Funktionen (Interface) + */ + +/* + * Contructors / Destructors for ident + */ + s_ident * +identNew (int idx, const char * key) +{ + int keyLen = (key == NULL) ? 2 : 2 + strlen (key); + s_ident * ident = (s_ident *) malloc (sizeof (s_ident)); + + ident->idx = idx; + ident->key = (char *) malloc (sizeof (char) * keyLen); + + ident->key[0] = ID_TYP_UNDEF; + ident->key[1] = '\0'; + + if (key != NULL) + strcpy (ident->key + 1, key); + + ident->queued = 0; + + return ident; +} + + s_ident * +identUndefNew (int idx, const char * key) +{ +#ifdef DEBUG2 + printf ("[!DEBUG!] identUndefNew: %d/%s\n", idx, key); +#endif + + return identNew (idx, key); +} + + s_ident * +identExpNew (int idx, const char * key, s_expVal * val) +{ + s_ident * ident = identNew (idx, key); + +#ifdef DEBUG2 + printf ("[!DEBUG!] identExpNew: %d/%s\n", idx, key); +#endif + + ident->key[0] = ID_TYP_EXP; + ident->val.base = expValueClone (val); + + return ident; +} + + s_ident * +identIdlNew (int idx, const char * key, s_identList * val) +{ + s_ident * ident = identNew (idx, key); + +#ifdef DEBUG2 + printf ("[!DEBUG!] identIdlNew: %d/%s\n", idx, key); +#endif + + ident->key[0] = ID_TYP_IDL; + ident->val.idl = val; + + return ident; +} + + void +identFree (s_ident * id) +{ +#ifdef DEBUG2 + printf ("[!DEBUG!] identFree: %d/%s\n", id->idx, id->key); +#endif + + switch (identGetType (id)) + { + case ID_TYP_EXP: expValueFree (id->val.base); break; + case ID_TYP_IDL: identListFree (id->val.idl); break; + } + + free (id->key); + free (id); +} + +/* + * analyse ident + */ + int +identIsQueued (s_ident * id) +{ + return id->queued; +} + + void +identEnqueue (s_ident * id) +{ + id->queued ++; +} + + void +identDequeue (s_ident * id) +{ + id->queued --; +} + + int +identGetType (s_ident * id) +{ + return id->key[0]; +} + + char * +identGetKey (s_ident * id) +{ + return id->key + 1; +} + + int +identGetIdx (s_ident * id) +{ + return id->idx; +} + +/* identifier to value */ + s_expVal * +identExp (s_ident * id) +{ + s_expVal * ret = NULL; + + if (id == NULL) + exitError (ERR_UNDEF_VAR, identGetKey (id)); + + if (identGetType (id) == ID_TYP_EXP) + { + ret = expValueClone (id->val.base); + } + + return ret; +} + + s_identList * +identIdl (s_ident * id) +{ + s_identList * ret = NULL; + + if (identGetType (id) == ID_TYP_IDL) + { + ret = id->val.idl; + } + + return ret; +} + + s_ident * +identSetExp (s_ident * id, s_expVal * val) +{ + switch (identGetType (id)) + { + case ID_TYP_EXP: expValueFree (id->val.base); break; + case ID_TYP_IDL: identListFree (id->val.idl); break; + } + + id->key[0] = ID_TYP_EXP; + id->val.base = expValueClone (val); + + return id; +} + + s_ident * +identSetIdl (s_ident * id, s_identList * val) +{ + switch (identGetType (id)) + { + case ID_TYP_EXP: expValueFree (id->val.base); + case ID_TYP_IDL: identListFree (id->val.idl); + } + + id->key[0] = ID_TYP_IDL; + id->val.idl = val; + + return id; +} diff --git a/src/identList.c b/src/identList.c new file mode 100644 index 0000000..3c87480 --- /dev/null +++ b/src/identList.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + + +struct identList +{ + s_bbTree * idIdx; + s_bbTree * idHash; +}; + + +/* + * statische Funktionen (interner gebrauch) + */ +static + int +idHashCmp (void * _a, void * _b) +{ + s_ident * a = (s_ident *) _a; + s_ident * b = (s_ident *) _b; + + return strcmp (identGetKey (a), identGetKey (b)); +} + +static + int +idIdxCmp (void * _a, void * _b) +{ + s_ident * a = (s_ident *) _a; + s_ident * b = (s_ident *) _b; + + return identGetIdx (a) - identGetIdx (b); +} + + +/* + * nicht statische Funktionen (Interface) + */ + +/* + * Contructors / Destructors for identList + */ + s_identList * +identListNew (void) +{ + s_identList * ret = (s_identList *) malloc (sizeof (s_identList)); + + ret->idIdx = bbTreeNew (idIdxCmp); + ret->idHash = bbTreeNew (idHashCmp); + + return ret; +} + +void +identListFree (s_identList * l) +{ + s_ident ** idArray, + ** _run; + + for (_run = idArray = (s_ident **) identListToArray (l); + *_run != NULL; + _run++) + { + identDequeue (*_run); + if (! identIsQueued (*_run)) + identFree (*_run); + } + + free (idArray); + + bbTreeFree (l->idIdx); + bbTreeFree (l->idHash); + + free (l); +} + +/* + * insertions or deletion into a identList + */ + s_ident * +identListPutVal (s_identList * l, s_ident * val) +{ + s_ident * oldVal; + int idx = identGetIdx (val); + char * key = identGetKey (val); + + identEnqueue (val); + + if ((idx < 0 && key[0] == '\0') || idx != -1 && key[0] != '\0') + /* calling error: either key or idx must be valid. But not both. */ + return NULL; + + if (idx >= 0) + oldVal = (s_ident *) bbTreeInsert (l->idIdx, val); + else + oldVal = (s_ident *) bbTreeInsert (l->idHash, val); + + if (oldVal != NULL) + /* + * these are few lines with a lot behind them. The not obvious question + * here is: What happens if oldval points to the same address than val? + * well, this could only happen if val was was formally queued, because + * else oldVal would be NULL. Knowing this makes clear that the queue + * state is not changed at all, because first it was increased above with + * identEnqueue and the it will be decreased in this if block again. But as + * it was formally queued it will not be freed (Good)! + */ + { + identDequeue (oldVal); + if (! identIsQueued (oldVal)) + identFree (oldVal); + } + + return val; +} + + s_ident * +identListPutExpByIdx (s_identList * l, int idx, s_expVal * val) +{ + return identListPutVal (l, identExpNew (idx, NULL, val)); +} + + s_ident * +identListPutIdlByIdx (s_identList * l, int idx, s_identList * val) +{ + return identListPutVal (l, identIdlNew (idx, NULL, val)); +} + + s_ident * +identListPutExpByKey (s_identList * l, const char * key, s_expVal * val) +{ + return identListPutVal (l, identExpNew (-1, key, val)); +} + + s_ident * +identListPutIdlByKey (s_identList * l, const char * key, s_identList * val) +{ + return identListPutVal (l, identIdlNew (-1, key, val)); +} + + void +identListRemoveByIdx (s_identList * l, int idx) +{ + s_ident * seek = (s_ident *) identNew (idx, NULL); + s_ident * val = bbTreeRemove (l->idIdx, seek); + +#ifdef DEBUG2 + printf ("[!DEBUG!] seek (remove) identNew: %d/%s\n", idx, ""); +#endif + + identFree (seek); + + if (val != NULL) + { + identDequeue (val); + if (! identIsQueued (val)) + identFree (val); + } +} + + void +identListRemoveByKey (s_identList * l, const char * key) +{ + s_ident * seek = (s_ident *) identNew (-1, key); + s_ident * val = bbTreeRemove (l->idIdx, seek); + +#ifdef DEBUG2 + printf ("[!DEBUG!] seek (remove) identNew: %d/%s\n", -1, key); +#endif + + identFree (seek); + + if (val != NULL) + { + identDequeue (val); + if (! identIsQueued (val)) + identFree (val); + } +} + +/* + * seeking in identList + */ + s_ident * +identListSeekIdx (s_identList * l, int idx) +{ + s_ident * seek = (s_ident *) identNew (idx, NULL); + s_ident * val = (s_ident *) bbTreeSeek (l->idIdx, seek); + +#ifdef DEBUG2 + printf ("[!DEBUG!] seek identNew: %d/%s\n", idx, ""); +#endif + + identFree (seek); + + return val; +} + + s_ident * +identListSeekKey (s_identList * l, const char * key) +{ + s_ident * seek = (s_ident *) identNew (-1, key); + s_ident * val = (s_ident *) bbTreeSeek (l->idHash, seek); + +#ifdef DEBUG2 + printf ("[!DEBUG!] seek identNew: %d/%s\n", -1, key); +#endif + + identFree (seek); + + return val; +} + +/* + * identList to other DataStructures + */ + s_ident ** +identListToArray (s_identList * l) +{ + int idIdxLen = bbTreeSize (l->idIdx); + int idHashLen = bbTreeSize (l->idHash); + int retLen = idIdxLen + idHashLen + 1; + s_ident ** ret = (s_ident **) malloc (sizeof (s_ident *) * retLen); + + memset (ret, 0, sizeof (s_ident **) * retLen); + + bbTreeInOrder (l->idIdx, (void **) ret); + bbTreeInOrder (l->idHash, (void **) &(ret[idIdxLen])); + + return ret; +} diff --git a/src/statement.c b/src/statement.c new file mode 100644 index 0000000..d74c615 --- /dev/null +++ b/src/statement.c @@ -0,0 +1,460 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Deklaration und Definition + */ +#include + +struct stmt +{ + int sId; + s_stmtQueue * sQueue; + u_stmtType sConst; + int sConstTyp; +}; + +/* + * statische Funktionen (interner gebrauch) + */ +static +inline + u_stmtType +stmtEval (s_stmt * stmt, s_block * actBlock, int op) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * op1 = stmtDo (stmtQueueGet (args, 0), actBlock).eVal, + * op2 = stmtDo (stmtQueueGet (args, 1), actBlock).eVal, + * ret; + + ret = evalExpr (op, op1, op2); + + if (op1 != NULL) expValueFree (op1); + if (op2 != NULL) expValueFree (op2); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtIdentVar (s_stmt * stmt, s_block * actBlock) +{ + s_ident * ret = NULL; + + s_stmtQueue * args = stmt->sQueue; + s_expVal * _op = stmtDo (stmtQueueGet (args, 0), actBlock).eVal; + char * op = expValueString (_op); + s_block * run = actBlock; + + while (ret == NULL && run != NULL) + { + ret = identListSeekKey (blockIdl (run), op); + run = blockPrev (run); + } + + if (ret == NULL) + ret = identListPutVal (blockIdl (actBlock), identUndefNew (-1, op)); + + expValueFree (_op); + free (op); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtIdentArray (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_ident * op1 = stmtDo (stmtQueueGet (args, 0), actBlock).idVal; + s_expVal * op2 = stmtDo (stmtQueueGet (args, 1), actBlock).eVal; + s_ident * ret; + + ret = getArray (op1, op2); + + if (op2 != NULL) expValueFree (op2); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtIdentVal (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_ident * op1 = stmtDo (stmtQueueGet (args, 0), actBlock).idVal; + + return (u_stmtType) identExp (op1); +} + +static +inline + u_stmtType +stmtEvalComp (s_stmt * stmt, s_block * actBlock, int op) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * op1 = stmtDo (stmtQueueGet (args, 0), actBlock).eVal, + * op2 = stmtDo (stmtQueueGet (args, 1), actBlock).eVal; + int ret; + + ret = evalComp (op, op1, op2); + + if (op1 != NULL) expValueFree (op1); + if (op2 != NULL) expValueFree (op2); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtAssign (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_ident * op1 = stmtDo (stmtQueueGet (args, 0), actBlock).idVal; + s_expVal * op2 = stmtDo (stmtQueueGet (args, 1), actBlock).eVal, + * ret; + + if (op1 == NULL) + op1 = getVariable (NULL, NULL); + + ret = assign (op1, op2); + + if (op2 != NULL) expValueFree (op2); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtPrint (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * op = stmtDo (stmtQueueGet (args, 0), actBlock).eVal; + + if (op != NULL) + { + printExpr (op); + expValueFree (op); + } + + return (u_stmtType) 0; +} + +static +inline + u_stmtType +stmtEvalCondExpr (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * op = stmtDo (stmtQueueGet (args, 0), actBlock).eVal; + int ret; + + ret = evalCondExpr (op); + + if (op != NULL) expValueFree (op); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtEvalCond (s_stmt * stmt, s_block * actBlock, int op) +{ + s_stmtQueue * args = stmt->sQueue; + int op1 = stmtDo (stmtQueueGet (args, 0), actBlock).cond; + + switch (op) + { + case LOGAND: + { + int op2 = stmtDo (stmtQueueGet (args, 1), actBlock).cond; + return (u_stmtType) (op1 && op2); + } + + case LOGOR: + { + int op2 = stmtDo (stmtQueueGet (args, 1), actBlock).cond; + return (u_stmtType) (op1 || op2); + } + + case LOGNEG: + return (u_stmtType) (! op1); + } +} + +static +inline + u_stmtType +stmtCastInt (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * op = stmtDo (stmtQueueGet (args, 0), actBlock).eVal, + * ret; + + ret = castExprToInt (op); + + if (op != NULL) expValueFree (op); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtCastFloat (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * op = stmtDo (stmtQueueGet (args, 0), actBlock).eVal, + * ret; + + ret = castExprToFloat (op); + + if (op != NULL) expValueFree (op); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtCastString (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * op = stmtDo (stmtQueueGet (args, 0), actBlock).eVal, + * ret; + + ret = castExprToString (op); + + if (op != NULL) expValueFree (op); + + return (u_stmtType) ret; +} + +static +inline + u_stmtType +stmtBlock (s_stmt * stmt, s_block * actBlock) +{ + unsigned int i; + + s_stmtQueue * gIds = stmtQueueGet (stmt->sQueue, 0)->sQueue; + s_stmtQueue * args = stmtQueueGet (stmt->sQueue, 1)->sQueue; + s_block * gBlock = NULL; + + gBlock = actBlock = blockPush (&actBlock, blockNew (args)); + + /* find the global block */ + while (blockPrev (gBlock) != NULL) + gBlock = blockPrev (gBlock); + + if (gIds != NULL) + { + for (i = 0; i < stmtQueueGetSize (gIds); i++) + { + s_expVal * tmp = stmtDo (stmtQueueGet (gIds, i), actBlock).eVal; + char * _id; + s_ident * id; + + if (tmp == NULL) + exitError (0); + + _id = expValueString (tmp); + id = identListSeekKey (blockGetIdl (gBlock), _id); + expValueFree (tmp); + free (_id); + + if (id == NULL) + exitError (0); + + blockSetNonLocalId (args, id); + } + } + + blockDo (actBlock); + blockFree (actBlock); + + return (u_stmtType) 0; +} + +static +inline + u_stmtType +stmtIf (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + int cond = stmtDo (stmtQueueGet (args, 0), actBlock).cond; + s_stmt * _do; + + if (cond) + _do = stmtQueueGet (args, 1); + else + _do = stmtQueueGet (args, 2); + + if (_do != NULL) + stmtDo (_do); + + return (u_stmtType) 0; +} + +static +inline + u_stmtType +stmtForeach (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * _id = stmtDo (stmtQueueGet (args, 0), actBlock).eVal, + * _key = stmtDo (stmtQueueGet (args, 1), actBlock).eVal, + * _val = stmtDo (stmtQueueGet (args, 2), actBlock).eVal; + char * id = expValueString (_id); + char * key = expValueString (_key); + char * val = expValueString (_val); + + printf ("[DEBUG]found foreach statement: id=%s, key=%s, val=%s\n", + id, key, val); + + free (id); + free (key); + free (val); + + expValueFree (_id); + expValueFree (_key); + expValueFree (_val); + + return (u_stmtType) 0; +} + +static +inline + u_stmtType +stmtRepeat (s_stmt * stmt, s_block * actBlock) +{ + s_stmtQueue * args = stmt->sQueue; + s_expVal * _id = stmtDo (stmtQueueGet (args, 0), actBlock).eVal, + * _count = stmtDo (stmtQueueGet (args, 1), actBlock).eVal; + char * id = expValueString (_id); + int count = expValueInt (_count); + + printf ("[DEBUG]found repeat statement: id=%s, count=%d\n", id, count); + + free (id); + + expValueFree (_id); + expValueFree (_count); + + return (u_stmtType) 0; +} + +/* + * Interface + */ + s_stmt * +stmtNew (int id, s_stmtQueue * queue, int conTyp, u_stmtType con) +{ + s_stmt * new = (s_stmt *) malloc (sizeof (s_stmt)); + + new->sId = id; + new->sQueue = queue; + new->sConstTyp = conTyp; + new->sConst = con; + + return new; +} + + s_stmtQueue * +stmtGetArgs (s_stmt * stmt) +{ + return stmt->sQueue; +} + + u_stmtType +stmtGetVal (s_stmt * stmt) +{ + return stmt->sConst; +} + + int +stmtGetConstTyp (s_stmt * stmt) +{ + return stmt->sConstTyp; +} + + void +stmtFree (s_stmt * stmt) +{ + if (stmt == NULL) + return; + + switch (stmt->sConstTyp) + { + case STYP_NONE: stmtQueueFree (stmt->sQueue); break; + case STYP_EVAL: expValueFree (stmt->sConst.eVal); break; + case STYP_IDVAL: identFree (stmt->sConst.idVal); break; + } + + free (stmt); +} + + u_stmtType +stmtDo (s_stmt * stmt, s_block * actBlock) +{ + if (stmt == NULL) + return (u_stmtType) 0; + + switch (stmt->sId) + { + case STMT_CONST: return (u_stmtType) expValueClone (stmt->sConst.eVal); + case STMT_BLOCK: return stmtBlock (stmt, actBlock); + + case STMT_PRINT: return stmtPrint (stmt, actBlock); + case STMT_IF: return stmtIf (stmt, actBlock); + case STMT_FOREACH: return stmtForeach (stmt, actBlock); + case STMT_REPEAT: return stmtRepeat (stmt, actBlock); + case STMT_ASSIGN: return stmtAssign (stmt, actBlock); + case STMT_UNSET: return (u_stmtType) 0; + + case STMT_EVAL_PLUS: return stmtEval (stmt, actBlock, PLUS); + case STMT_EVAL_MINUS: return stmtEval (stmt, actBlock, MINUS); + case STMT_EVAL_TIMES: return stmtEval (stmt, actBlock, TIMES); + case STMT_EVAL_OVER: return stmtEval (stmt, actBlock, OVER); + case STMT_EVAL_MODULO: return stmtEval (stmt, actBlock, MODULO); + case STMT_EVAL_NEG: return stmtEval (stmt, actBlock, NEG); + + case STMT_IDENT_VAR: return stmtIdentVar (stmt, actBlock); + case STMT_IDENT_ARRAY: return stmtIdentArray (stmt, actBlock); + case STMT_IDENT_VAL: return stmtIdentVal (stmt, actBlock); + + case STMT_CAST_INT: return stmtCastInt (stmt, actBlock); + case STMT_CAST_FLOAT: return stmtCastFloat (stmt, actBlock); + case STMT_CAST_STRING: return stmtCastString (stmt, actBlock); + + case STMT_COMP_EQ: return stmtEvalComp (stmt, actBlock, EQ); + case STMT_COMP_NE: return stmtEvalComp (stmt, actBlock, NE); + case STMT_COMP_LT: return stmtEvalComp (stmt, actBlock, LT); + case STMT_COMP_GT: return stmtEvalComp (stmt, actBlock, GT); + case STMT_COMP_LE: return stmtEvalComp (stmt, actBlock, LE); + case STMT_COMP_GE: return stmtEvalComp (stmt, actBlock, GE); + + case STMT_COND_EXPR: return stmtEvalCondExpr (stmt, actBlock); + case STMT_COND_AND: return stmtEvalCond (stmt, actBlock, LOGAND); + case STMT_COND_OR: return stmtEvalCond (stmt, actBlock, LOGOR); + case STMT_COND_NEG: return stmtEvalCond (stmt, actBlock, LOGNEG); + } +} diff --git a/src/stmtQueue.c b/src/stmtQueue.c new file mode 100644 index 0000000..7b1250a --- /dev/null +++ b/src/stmtQueue.c @@ -0,0 +1,127 @@ +#include +#include + +#include +#include +#include + +#include + +/* give the queue an initial size for 10 statements */ +#define QUEUE_GROW_SIZE 10 + + +struct stmtQueue +{ + s_stmt ** stmts; /* a dynamically growing array of statements. */ + + unsigned int size; /* the actual size of the array in statements */ + unsigned int maxIdx; /* the maximum index used in the array. */ +}; + + s_stmtQueue * +stmtQueueNew (void) +{ + s_stmtQueue * new = (s_stmtQueue *) malloc (sizeof (s_stmtQueue)); + + new->size = QUEUE_GROW_SIZE; + new->maxIdx = 0; + new->stmts = (s_stmt **) calloc (sizeof (s_stmt *), new->size); + memset (new->stmts, 0, sizeof (s_stmt *) * new->size); + + return new; +} + +/* + * This concat does not change a or b, as opposed to the c strcat function + */ + s_stmtQueue * +stmtQueueConcat (s_stmtQueue * a, s_stmtQueue * b) +{ + s_stmtQueue * new = (s_stmtQueue *) malloc (sizeof (s_stmtQueue)); + + new->size = a->size + b->size; + new->maxIdx = a->maxIdx + b->maxIdx; + new->stmts = (s_stmt **) calloc (sizeof (s_stmt *), new->size); + memset (new->stmts, 0, sizeof (s_stmt *) * new->size); + + memcpy (new->stmts, a->stmts, sizeof (s_stmt *) * a->maxIdx); + memcpy (&(new->stmts[a->maxIdx]), b->stmts, sizeof (s_stmt *) * b->maxIdx); + + return new; +} + + void +stmtQueueFree (s_stmtQueue * sQueue) +{ + unsigned int i; + + if (sQueue == NULL) + return; + + /* freeing the queue is the final step. All stmts should be freed too! */ + for (i = 0; i < sQueue->maxIdx; i++) + stmtFree (sQueue->stmts [i]); + + free (sQueue->stmts); + free (sQueue); +} + + void +stmtQueueEnqueue (s_stmtQueue * sQueue, s_stmt * stmt) +{ + if (sQueue->maxIdx >= sQueue->size) + { + s_stmt ** stmtsOld = sQueue->stmts; + unsigned int newSize = sQueue->size + QUEUE_GROW_SIZE; + + sQueue->stmts = (s_stmt **) calloc (sizeof (s_stmt *), newSize); + memcpy (sQueue->stmts, stmtsOld, sizeof (s_stmt **) * sQueue->size); + free (stmtsOld); /* free the old queue but keep the statements */ + memset ( + &(sQueue->stmts[sQueue->size]), + 0, + sizeof (s_stmt **) * QUEUE_GROW_SIZE); + sQueue->size = newSize;; + } + + sQueue->stmts[sQueue->maxIdx ++] = stmt; +} + + s_stmt * +stmtQueueDequeue (s_stmtQueue * sQueue) +{ + s_stmt * ret = sQueue->stmts[sQueue->maxIdx - 1]; + + sQueue->stmts[-- sQueue->maxIdx] = NULL; + + return ret; +} + + s_stmt * +stmtQueueGet (s_stmtQueue * sQueue, unsigned int idx) +{ + if (idx < sQueue->size) + return sQueue->stmts [idx]; + else + return NULL; +} + + void +stmtQueueDo (s_stmtQueue * sQueue) +{ + int i; + + if (sQueue == NULL) + return; + + for (i = 0; i < sQueue->maxIdx; i++) + stmtDo (sQueue->stmts[i]); +} + + unsigned + int +stmtQueueGetSize (s_stmtQueue * sQueue) +{ + return sQueue->size; +} diff --git a/src/tepal.c b/src/tepal.c new file mode 100644 index 0000000..501ec19 --- /dev/null +++ b/src/tepal.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +char * tepalErrMsg[] = +{ + "[ERROR] using uninitialized variable: %s\n", + "[ERROR] using array identifier without index: %s\n", + "[ERROR] unknown string operator: %c\n", + "[ERROR] unknown float operator: %c\n" +}; + + void +exitError (int errNum, ...) +{ + va_list ap; + + va_start (ap, errNum); + + switch (errNum) + { + case ERR_UNDEF_VAR: + fprintf (stderr, tepalErrMsg[errNum], va_arg(ap, char *)); + break; + + case ERR_NO_INDEX: + fprintf (stderr, tepalErrMsg[errNum], va_arg(ap, char *)); + break; + + case ERR_STRING_OPERATOR: + fprintf (stderr, tepalErrMsg[errNum], va_arg(ap, int)); + break; + + case ERR_FLOAT_OPERATOR: + fprintf (stderr, tepalErrMsg[errNum], va_arg(ap, int)); + break; + } + + va_end (ap); + exit (errNum); +} + +void +printExpr (s_expVal * val) +{ + switch (expValueGetType (val)) + { + case EXP_TYP_INT: printf ("%d", expValueInt (val)); break; + case EXP_TYP_FLOAT: printf ("%f", expValueFloat (val)); break; + case EXP_TYP_STRING: + { + char * v = expValueString (val); + printf (v); + free (v); + } + } +} + diff --git a/src/tepal_pars.y b/src/tepal_pars.y new file mode 100644 index 0000000..b60534a --- /dev/null +++ b/src/tepal_pars.y @@ -0,0 +1,575 @@ +%{ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int yylex (void); + + int +yywrap () +{ + return 1; +} + + void +yyerror (char const * s) +{ + fprintf(stderr, "%s\n", s); +} + +/* + * globale Variablen + */ +extern FILE * yyin; +extern s_block * _globalBlock_; + +s_stmtQueue * astRoot; + +/* + * statische Funktionen (zum lokalen gebrauch) + */ +static +inline + s_stmtQueue * +enqStmt (s_stmtQueue * sQueue, s_stmt * stmt) +{ + s_stmtQueue * ret = (sQueue == NULL) ? stmtQueueNew () : sQueue; + + stmtQueueEnqueue (ret, stmt); + return ret; +} + +static +inline + s_stmtQueue * +enqGlobId (s_stmtQueue * sQueue, char * id) +{ + s_stmtQueue * ret = (sQueue == NULL) ? stmtQueueNew () : sQueue; + s_stmt * val = stmtNew (STMT_CONST, NULL, STYP_EVAL, (u_stmtType) id); + + stmtQueueEnqueue (ret, id); + + return ret; +} + +static +inline + s_stmtQueue * +genBlockQue (s_stmtQueue * _gI, s_stmtQueue * _st) +{ + s_stmtQueue * ret = stmtQueueNew (); + s_stmt * gIds = stmtNew (STMT_BLOCK, _gI, STYP_NONE, (u_stmtType) 0); + s_stmt * stmts = stmtNew (STMT_BLOCK, _st, STYP_NONE, (u_stmtType) 0); + + stmtQueueEnqueue (ret, gIds); + stmtQueueEnqueue (ret, stmts); + + return ret; +} + +static +inline + s_stmt * +genIntStmt (long iVal) +{ + return stmtNew ( + STMT_CONST, + NULL, + STYP_EVAL, + (u_stmtType) expValueIntNew (iVal)); +} + +static +inline + s_stmt * +genFloatStmt (double fVal) +{ + return stmtNew ( + STMT_CONST, + NULL, + STYP_EVAL, + (u_stmtType) expValueFloatNew (fVal)); +} + +static +inline + s_stmt * +genStringStmt (s_stmt * stmt, char * string) +{ + s_stmt * ret = NULL; + s_expVal * eVal = NULL; + + char * new = NULL; + + if (stmt != NULL) + { + char * old = expValueString (stmtGetVal (stmt).eVal); + size_t len = strlen (old) + strlen (string) + 1; + + new = (char *) calloc (sizeof (char), len); + strcpy (new, old); + strcat (new, string); + + stmtFree (stmt); + free (old); + } + else + { + new = (char *)calloc (sizeof (char), strlen (string) + 1); + strcpy (new, string); + } + + eVal = expValueStringNew (new); + ret = stmtNew (STMT_CONST, NULL, STYP_EVAL, (u_stmtType) eVal); + free (new); + + free (string); + + return ret; +} + +static +inline + s_stmt * +genBlockStmt (s_stmtQueue * sQueue) +{ + return stmtNew (STMT_BLOCK, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genPrintStmt (s_stmt * stmt) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, stmt); + return stmtNew (STMT_PRINT, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genIfStmt (s_stmt * cond, s_stmt * _then, s_stmt * _else) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, cond); + stmtQueueEnqueue (sQueue, _then); + stmtQueueEnqueue (sQueue, _else); + + return stmtNew (STMT_IF, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genRepStmt (char * _ident, long _count, s_stmt * stmt) +{ + u_stmtType _id = (u_stmtType) expValueStringNew (_ident); + u_stmtType _co = (u_stmtType) expValueIntNew (_count); + s_stmt * ident = stmtNew (STMT_CONST, NULL, STYP_EVAL, _id); + s_stmt * count = stmtNew (STMT_CONST, NULL, STYP_EVAL, _co); + + s_stmtQueue * sQueue = stmtQueueNew (); + + free (_ident); + + stmtQueueEnqueue (sQueue, ident); + stmtQueueEnqueue (sQueue, count); + stmtQueueEnqueue (sQueue, stmt); + + return stmtNew (STMT_REPEAT, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genForeStmt (char * _ident, char * _key, char * _val, s_stmt * stmt) +{ + u_stmtType _id = (u_stmtType) expValueStringNew (_ident); + u_stmtType _k = (u_stmtType) expValueStringNew (_key); + u_stmtType _v = (u_stmtType) expValueStringNew (_val); + s_stmt * ident = stmtNew (STMT_CONST, NULL, STYP_EVAL, _id); + s_stmt * key = stmtNew (STMT_CONST, NULL, STYP_EVAL, _k); + s_stmt * val = stmtNew (STMT_CONST, NULL, STYP_EVAL, _v); + + s_stmtQueue * sQueue = stmtQueueNew (); + + free (_ident); + free (_key); + free (_val); + + stmtQueueEnqueue (sQueue, ident); + stmtQueueEnqueue (sQueue, key); + stmtQueueEnqueue (sQueue, val); + stmtQueueEnqueue (sQueue, stmt); + + return stmtNew (STMT_FOREACH, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genCondExprStmt (s_stmt * stmt) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, stmt); + return stmtNew (STMT_COND_EXPR, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genOpStmt (int op, s_stmt * op1, s_stmt * op2) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + int stmtId; + + stmtQueueEnqueue (sQueue, op1); + stmtQueueEnqueue (sQueue, op2); + + switch (op) + { + case LOGNEG: stmtId = STMT_COND_NEG; break; + case LOGAND: stmtId = STMT_COND_AND; break; + case LOGOR: stmtId = STMT_COND_OR; break; + case EQ: stmtId = STMT_COMP_EQ; break; + case NE: stmtId = STMT_COMP_NE; break; + case LT: stmtId = STMT_COMP_LT; break; + case GT: stmtId = STMT_COMP_GT; break; + case LE: stmtId = STMT_COMP_LE; break; + case GE: stmtId = STMT_COMP_GE; break; + case NEG: stmtId = STMT_EVAL_NEG; break; + case PLUS: stmtId = STMT_EVAL_PLUS; break; + case MINUS: stmtId = STMT_EVAL_MINUS; break; + case TIMES: stmtId = STMT_EVAL_TIMES; break; + case OVER: stmtId = STMT_EVAL_OVER; break; + case MODULO: stmtId = STMT_EVAL_MODULO; break; + } + + return stmtNew (stmtId, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genAssignStmt (s_stmt * var, s_stmt * val) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, var); + stmtQueueEnqueue (sQueue, val); + + return stmtNew (STMT_ASSIGN, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genIdMkGlobStmt (s_stmtQueue * sQueue) +{ + return stmtNew (/*another ID here*/STMT_BLOCK, + sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genIdentVarStmt (char * _ident) +{ + u_stmtType _id = (u_stmtType) expValueStringNew (_ident); + s_stmt * ident = stmtNew (STMT_CONST, NULL, STYP_EVAL, _id); + + s_stmtQueue * sQueue = stmtQueueNew (); + + free (_ident); + + stmtQueueEnqueue (sQueue, ident); + return stmtNew (STMT_IDENT_VAR, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genIdentArrStmt (s_stmt * base, s_stmt * idx) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, base); + stmtQueueEnqueue (sQueue, idx); + + return stmtNew (STMT_IDENT_ARRAY, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genIdentValStmt (s_stmt * stmt) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, stmt); + return stmtNew (STMT_IDENT_VAL, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genCastIntStmt (s_stmt * stmt) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, stmt); + return stmtNew (STMT_CAST_INT, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genCastFloatStmt (s_stmt * stmt) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, stmt); + return stmtNew (STMT_CAST_FLOAT, sQueue, STYP_NONE, (u_stmtType) 0); +} + +static +inline + s_stmt * +genCastStringStmt (s_stmt * stmt) +{ + s_stmtQueue * sQueue = stmtQueueNew (); + + stmtQueueEnqueue (sQueue, stmt); + return stmtNew (STMT_CAST_STRING, sQueue, STYP_NONE, (u_stmtType) 0); +} + +%} + +%token STMT_END ';' REPEAT COUNT FOREACH AS IF ELSE BLOCK_END UNSET +%token ICAST FCAST SCAST GLOBAL /* for explicit casts */ +%token IDENT +%token HTML +%token INT +%token FLOAT +%token STRING +%token EOL + +%left LOGAND LOGOR +%left LOGNEG +%nonassoc NE EQ LT GT LE GE + +%right '=' +%left '+' '-' +%left '*' '/' '%' +%left NEG +%nonassoc '(' ')' + +%union { + long iVal; + double fVal; + char * cPtr; + struct stmt * stmt; + struct stmtQueue * sQue; +} + +/* Es wird wohl darauf hinauslaufen das alles erstmal ein stmt wird + und in den AST wandert, und erst dann ausgewertet wird. Anders + wird es wohl nicht gehen. */ +%type assig; +%type ident; +%type cond; +%type comp; +%type expr; +%type html; +%type block_stmt; +%type gdecl_block; +%type simple_stmt; +%type if_stmt; +%type rep_stmt; +%type fore_stmt; +%type stmt; +%type stmt_queue; +%type block_queue; +%type glob_decl; + +%expect 1 + +%start script + +%% + +script : stmt_queue { astRoot = $1; } +; + +stmt_queue : stmt { $$ = enqStmt (NULL, $1); } + | stmt_queue stmt { $$ = enqStmt ($1, $2); } +; + +stmt : simple_stmt + | block_stmt + | if_stmt + | rep_stmt + | fore_stmt + | stmt_end stmt { $$ = $2; } +; + +simple_stmt : html stmt_end { $$ = genPrintStmt ($1); } + | expr stmt_end { $$ = genPrintStmt ($1); } + | assig stmt_end +; + +html : HTML { $$ = genStringStmt (NULL, $1); } + | html HTML { $$ = genStringStmt ($1, $2); } +; + +stmt_end : STMT_END + | ';' +; + +block_stmt : ':' BLOCK_END { $$ = genBlockStmt (NULL); } + | ':' block_queue BLOCK_END { $$ = genBlockStmt ($2); } +; + +block_queue : stmt_queue { $$ = genBlockQue (NULL, $1); } + | gdecl_block stmt_queue { $$ = genBlockQue ($1, $2); } +; + +/* + * Here follows the definitions for the "globals definition block" + * This is more complicated than first guessed, because these are no + * normal statements as all other constructs are. Escpecially in those + * block a newline should not be interpreted as statmend-end. + * ------ + */ +gdecl_block : GLOBAL ':' glob_decl BLOCK_END + { $$ = $3); } +; + +glob_decl : IDENT { $$ = enqGlobId (NULL, $1); } + | glob_decl ',' IDENT { $$ = enqGlobId ($1, $3); } +; +/* + * ------ + */ + +/* here is 1 shift/reduce conflict, but thats ok. */ +if_stmt : IF '(' cond ')' stmt { $$ = genIfStmt ($3, $5, NULL); } + | IF '(' cond ')' stmt ELSE stmt + { $$ = genIfStmt ($3, $5, $7); } +; + +rep_stmt : REPEAT '(' IDENT COUNT '=' INT ')' stmt + { $$ = genRepStmt ($3, $6, $8); } +; + +fore_stmt : FOREACH '(' IDENT AS IDENT ',' IDENT ')' stmt + { $$ = genForeStmt ($3, $5, $7, $9); } +; + +cond : expr { $$ = genCondExprStmt ($1); } + | comp { $$ = $1; } + | '(' comp ')' { $$ = $2; } + | '!' cond %prec LOGNEG { $$ = genOpStmt (LOGNEG, $2, NULL); } + | '(' '!' cond ')' %prec LOGNEG + { $$ = genOpStmt (LOGNEG, $3, NULL); } + | cond LOGAND cond { $$ = genOpStmt (LOGAND, $1, $3); } + | '(' cond LOGAND cond ')' { $$ = genOpStmt (LOGAND, $2, $4); } + | cond LOGOR cond { $$ = genOpStmt (LOGOR, $1, $3); } + | '(' cond LOGOR cond ')' { $$ = genOpStmt (LOGOR, $2, $4); } +; + +comp : expr EQ expr { $$ = genOpStmt (EQ, $1, $3); } + | expr NE expr { $$ = genOpStmt (NE, $1, $3); } + | expr LT expr { $$ = genOpStmt (LT, $1, $3); } + | expr GT expr { $$ = genOpStmt (GT, $1, $3); } + | expr LE expr { $$ = genOpStmt (LE, $1, $3); } + | expr GE expr { $$ = genOpStmt (GE, $1, $3); } +; + +assig : ident '=' expr { $$ = genAssignStmt ($1, $3); } + | ident '=' assig { $$ = genAssignStmt ($1, $3); } +; + +ident : IDENT { $$ = genIdentVarStmt ($1); } + | ident '[' expr ']' { $$ = genIdentArrStmt ($1, $3); } +; + +expr : ident { $$ = genIdentValStmt ($1); } + | INT { $$ = genIntStmt ($1); } + | FLOAT { $$ = genFloatStmt ($1); } + | STRING { $$ = genStringStmt (NULL, $1); } + | EOL { $$ = genStringStmt (NULL, $1); } + + | '(' ICAST ')' expr { $$ = genCastIntStmt ($4); } + | '(' FCAST ')' expr { $$ = genCastFloatStmt ($4); } + | '(' SCAST ')' expr { $$ = genCastStringStmt ($4); } + | '(' expr ')' { $$ = $2; } + + | '-' expr %prec NEG { $$ = genOpStmt (NEG, $2, NULL); } + | expr '+' expr { $$ = genOpStmt (PLUS, $1, $3); } + | expr '-' expr { $$ = genOpStmt (MINUS, $1, $3); } + | expr '*' expr { $$ = genOpStmt (TIMES, $1, $3); } + | expr '/' expr { $$ = genOpStmt (OVER, $1, $3); } + | expr '%' expr { $$ = genOpStmt (MODULO, $1, $3); } +; + +%% + +int +main (int argc, void * argv []) +{ + if (argc >= 2) + { + if ((yyin = fopen (argv[1], "r")) == NULL) + { + fprintf (stderr, "Could not open input file: %s\n", argv[1]); + fprintf (stderr, "Using stdin\n"); + yyin = stdin; + } + } + /* + * normally we would read from stdin if no file is given but for + * demonstration purpose we read a file from a standard location. + */ + else + { + if ((yyin = fopen ("/var/www/localhost/tpl/index.tpl", "r")) == NULL) + { + fprintf (stderr, "Could not open input file: %s\n", argv[1]); + fprintf (stderr, "Using stdin\n"); + yyin = stdin; + } + } + + printf ("Content-type: text/html\n\n"); + + astRoot = NULL; + yyparse (); + + _globalBlock_ = blockNew (astRoot); + + blockDo (_globalBlock_); + + if (_globalBlock_ != NULL); + blockFree (_globalBlock_); + + if (argc >= 2) + fclose (yyin); +} diff --git a/src/tepal_scan.l b/src/tepal_scan.l new file mode 100644 index 0000000..8000069 --- /dev/null +++ b/src/tepal_scan.l @@ -0,0 +1,295 @@ +%{ +#include +#include +#include + +#include +%} + +%x TOK + +DIGITS [0-9]+ +INT {DIGITS} +FLOAT {DIGITS}(.{DIGITS})? +STRING ('[^']*')|(\"[^\"]*\") +IDENT [a-zA-Z][_0-9a-zA-Z]*|_[0-9a-zA-Z]+ +OPERATOR [+\-*/%=,!:\[\]\(\);] + +ICAST int +FCAST float +SCAST string + +S_TOK [ \t]*<# +E_TOK #> +TEXT (\<[^#].*)|([^\<]*) + +%% + +{TEXT} { + char tok[2]; + size_t len = strlen (yytext); + + yylval.cPtr = (char *) malloc (len + 2); + memset (yylval.cPtr, 0, len + 2); + memcpy (yylval.cPtr, yytext, len); + + tok[0] = input (); + tok[1] = input (); + + if (tok[1] == '#' || tok[0] == EOF) + { + unput ('#'); + unput ('<'); + } + else + { + if (tok[1] != EOF) + unput (tok[1]); + yylval.cPtr[len] = tok[0]; + } + + #ifdef DEBUG + printf ("[TOKEN] HTML\n"); + #endif + + return HTML; + } + +{S_TOK} { + BEGIN (TOK); + #ifdef DEBUG + printf ("[TOKEN] STMT_END {[ \\t]*<#}\n"); + #endif + return STMT_END; + } + +{E_TOK}\n? { + BEGIN (INITIAL); + + #ifdef DEBUG + printf ("[TOKEN] STMT_END {#>\\n?}\n"); + #endif + + return STMT_END; + } + +{OPERATOR} { + #ifdef DEBUG + printf ("[TOKEN] %c\n", yytext[0]); + #endif + yylval.iVal = yytext[0]; + return yytext[0]; + } + +== { + #ifdef DEBUG + printf ("[TOKEN] EQ\n"); + #endif + + return EQ; + } +!= { + #ifdef DEBUG + printf ("[TOKEN] NE\n"); + #endif + + return NE; + } +\< { + #ifdef DEBUG + printf ("[TOKEN] EQ\n"); + #endif + + return LT; + } +\> { + #ifdef DEBUG + printf ("[TOKEN] EQ\n"); + #endif + + return GT; + } +\<= { + #ifdef DEBUG + printf ("[TOKEN] EQ\n"); + #endif + + return LE; + } +\>= { + #ifdef DEBUG + printf ("[TOKEN] EQ\n"); + #endif + + return GE; + } + +&& { + #ifdef DEBUG + printf ("[TOKEN] LOGAND\n"); + #endif + + return LOGAND; + } +\|\| { + #ifdef DEBUG + printf ("[TOKEN] LOGOR\n"); + #endif + + return LOGOR; + } + +{INT} { + yylval.iVal = atol (yytext); + + #ifdef DEBUG + printf ("[TOKEN] INT\n"); + #endif + + return INT; + } + +{FLOAT} { + yylval.fVal = atof (yytext); + + #ifdef DEBUG + printf ("[TOKEN] FLOAT\n"); + #endif + + return FLOAT; + } + +{STRING} { + yylval.cPtr = (char *) malloc (strlen (yytext) - 1); + memset (yylval.cPtr, 0, strlen (yytext) - 1); + memcpy (yylval.cPtr, yytext + 1, strlen (yytext) - 2); + + #ifdef DEBUG + printf ("[TOKEN] STRING\n"); + #endif + + return STRING; + } + +repeat { + #ifdef DEBUG + printf ("[TOKEN] REPEAT\n"); + #endif + + return REPEAT; + } +count { + #ifdef DEBUG + printf ("[TOKEN] COUNT\n"); + #endif + + return COUNT; + } + +foreach { + #ifdef DEBUG + printf ("[TOKEN] FOREACH\n"); + #endif + + return FOREACH; + } +as { + #ifdef DEBUG + printf ("[TOKEN] AS\n"); + #endif + + return AS; + } + +if { + #ifdef DEBUG + printf ("[TOKEN] IF\n"); + #endif + + return IF; + } +else { + #ifdef DEBUG + printf ("[TOKEN] ELSE\n"); + #endif + + return ELSE; + } + +end { + #ifdef DEBUG + printf ("[TOKEN] BLOCK_END\n"); + #endif + + return BLOCK_END; + } + +unset { + #ifdef DEBUG + printf ("[TOKEN] UNSET\n"); + #endif + + return UNSET; + } + +eol { + yylval.cPtr = (char *) calloc (sizeof (char), 2); + yylval.cPtr[0] = '\n'; + yylval.cPtr[1] = '\0'; + #ifdef DEBUG + printf ("[TOKEN] EOL\n"); + #endif + + return EOL; + } + +parent { + #ifdef DEBUG + printf ("[TOKEN] PARENT\n"); + #endif + + return PARENT; + } + +global { + #ifdef DEBUG + printf ("[TOKEN] GLOBAL\n"); + #endif + + return GLOBAL; + } + +{ICAST} { + #ifdef DEBUG + printf ("[TOKEN] ICAST\n"); + #endif + + return ICAST; + } +{FCAST} { + #ifdef DEBUG + printf ("[TOKEN] FCAST\n"); + #endif + + return FCAST; + } +{SCAST} { + #ifdef DEBUG + printf ("[TOKEN] SCAST\n"); + #endif + + return SCAST; + } + +{IDENT} { + yylval.cPtr = (char *) malloc (strlen (yytext) + 1); + strcpy (yylval.cPtr, yytext); + + #ifdef DEBUG + printf ("[TOKEN] IDENT\n"); + #endif + + return IDENT; + } + +[ \t\r\n] { /* eat tokens */ } diff --git a/src/variable.c b/src/variable.c new file mode 100644 index 0000000..f09e1c2 --- /dev/null +++ b/src/variable.c @@ -0,0 +1,56 @@ +#include +#include + +#include +#include +#include +#include + + + s_ident * +getVariable (identList * iList, char * id) +{ + return identListSeekKey (iList, id); +} + + s_ident * +getArray (s_ident * var, s_expVal * eVal) +{ + s_ident * ret = NULL; + + /* generate new idl if ident isn't, discard prev val */ + if (identGetType (var) != ID_TYP_IDL) + identSetIdl (var, identListNew (NULL)); + + /* now seek or generate the actual ident */ + switch (expValueGetType (eVal)) + { + case EXP_TYP_INT: + { + int idx = expValueInt (eVal); + + ret = identListSeekIdx (identIdl (var), idx); + + if (ret == NULL) + ret = identListPutVal ( + identIdl (var), identUndefNew (idx, NULL)); + + break; + } + + case EXP_TYP_STRING: + { + char * key = expValueString (eVal); + + ret = identListSeekKey (identIdl (var), key); + + if (ret == NULL) + ret = identListPutVal ( + identIdl (var), identUndefNew (-1, key)); + + free (key); + } + } + + return ret; +}