From 41f4765afb8d8d4749b08beefb8e0636cfce51ca Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 13 Dec 2006 14:25:02 +0000 Subject: [PATCH] Initial repository layout --- AUTHORS | 1 + ChangeLog | 60 +++++ Makefile.am | 9 + NEWS | 0 README | 21 ++ TODO | 63 +++++ autoclean.sh | 25 ++ autogen.sh | 10 + configure.ac | 46 ++++ include/Makefile.am | 6 + include/assign.h | 9 + include/bbtree.h | 66 +++++ include/block.h | 18 ++ include/cast.h | 10 + include/evalCond.h | 9 + include/evalExpr.h | 15 ++ include/expValue.h | 31 +++ include/helper.h | 7 + include/ident.h | 35 +++ include/identList.h | 29 +++ include/statement.h | 74 ++++++ include/stmtQueue.h | 22 ++ include/tepal.h | 14 ++ include/variable.h | 11 + index.tpl | 101 ++++++++ src/Makefile.am | 25 ++ src/assign.c | 24 ++ src/bbtree.c | 411 +++++++++++++++++++++++++++++++ src/block.c | 82 +++++++ src/cast.c | 30 +++ src/evalCond.c | 113 +++++++++ src/evalExpr.c | 145 +++++++++++ src/expValue.c | 150 ++++++++++++ src/ident.c | 217 +++++++++++++++++ src/identList.c | 238 ++++++++++++++++++ src/statement.c | 460 +++++++++++++++++++++++++++++++++++ src/stmtQueue.c | 127 ++++++++++ src/tepal.c | 65 +++++ src/tepal_pars.y | 575 ++++++++++++++++++++++++++++++++++++++++++++ src/tepal_scan.l | 295 +++++++++++++++++++++++ src/variable.c | 56 +++++ 41 files changed, 3705 insertions(+) create mode 100644 AUTHORS create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100755 autoclean.sh create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 include/Makefile.am create mode 100644 include/assign.h create mode 100644 include/bbtree.h create mode 100644 include/block.h create mode 100644 include/cast.h create mode 100644 include/evalCond.h create mode 100644 include/evalExpr.h create mode 100644 include/expValue.h create mode 100644 include/helper.h create mode 100644 include/ident.h create mode 100644 include/identList.h create mode 100644 include/statement.h create mode 100644 include/stmtQueue.h create mode 100644 include/tepal.h create mode 100644 include/variable.h create mode 100644 index.tpl create mode 100644 src/Makefile.am create mode 100644 src/assign.c create mode 100644 src/bbtree.c create mode 100644 src/block.c create mode 100644 src/cast.c create mode 100644 src/evalCond.c create mode 100644 src/evalExpr.c create mode 100644 src/expValue.c create mode 100644 src/ident.c create mode 100644 src/identList.c create mode 100644 src/statement.c create mode 100644 src/stmtQueue.c create mode 100644 src/tepal.c create mode 100644 src/tepal_pars.y create mode 100644 src/tepal_scan.l create mode 100644 src/variable.c 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; +}