commit
41f4765afb
41 changed files with 3705 additions and 0 deletions
-
1AUTHORS
-
60ChangeLog
-
9Makefile.am
-
0NEWS
-
21README
-
63TODO
-
25autoclean.sh
-
10autogen.sh
-
46configure.ac
-
6include/Makefile.am
-
9include/assign.h
-
66include/bbtree.h
-
18include/block.h
-
10include/cast.h
-
9include/evalCond.h
-
15include/evalExpr.h
-
31include/expValue.h
-
7include/helper.h
-
35include/ident.h
-
29include/identList.h
-
74include/statement.h
-
22include/stmtQueue.h
-
14include/tepal.h
-
11include/variable.h
-
101index.tpl
-
25src/Makefile.am
-
24src/assign.c
-
411src/bbtree.c
-
82src/block.c
-
30src/cast.c
-
113src/evalCond.c
-
145src/evalExpr.c
-
150src/expValue.c
-
217src/ident.c
-
238src/identList.c
-
460src/statement.c
-
127src/stmtQueue.c
-
65src/tepal.c
-
575src/tepal_pars.y
-
295src/tepal_scan.l
-
56src/variable.c
@ -0,0 +1 @@ |
|||
Georg Steffers <georg@steffers.org> |
|||
@ -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. |
|||
@ -0,0 +1,9 @@ |
|||
DEFS = -DHAS_CONFIG @DEFS@ |
|||
|
|||
nobase_include_HEADERS = index.tpl |
|||
|
|||
ACLOCAL_AMFLAGS = -I m4 |
|||
|
|||
# EXTRA_DIST =
|
|||
|
|||
SUBDIRS = src include |
|||
@ -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. |
|||
@ -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. |
|||
@ -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 |
|||
@ -0,0 +1,10 @@ |
|||
#!/bin/sh |
|||
# Script for regenerating all autogenerated files. |
|||
|
|||
mkdir config |
|||
|
|||
aclocal |
|||
autoconf |
|||
autoheader |
|||
libtoolize -c -f |
|||
automake -a -c |
|||
@ -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 |
|||
@ -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 |
|||
|
|||
@ -0,0 +1,9 @@ |
|||
#ifndef _ASSIGN_H_ |
|||
#define _ASSIGN_H_ |
|||
|
|||
#include <ident.h> |
|||
#include <expValue.h> |
|||
|
|||
s_expVal * assign (s_ident *, s_expVal *); |
|||
|
|||
#endif /* _ASSIGN_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_ */ |
|||
@ -0,0 +1,18 @@ |
|||
#ifndef _BLOCK_H_ |
|||
#define _BLOCK_H_ |
|||
|
|||
typedef struct block s_block; |
|||
|
|||
#include <identList.h> |
|||
#include <stmtQueue.h> |
|||
|
|||
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_ */ |
|||
@ -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_ */ |
|||
@ -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_ */ |
|||
@ -0,0 +1,15 @@ |
|||
#ifndef _EVAL_EXPR_H_ |
|||
#define _EVAL_EXPR_H_ |
|||
|
|||
#include <tepal_pars.h> |
|||
#include <expValue.h> |
|||
|
|||
#define PLUS '+' |
|||
#define MINUS '-' |
|||
#define TIMES '*' |
|||
#define OVER '/' |
|||
#define MODULO '%' |
|||
|
|||
s_expVal * evalExpr (int, s_expVal *, s_expVal *); |
|||
|
|||
#endif /* _EVAL_EXPR_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_ */ |
|||
@ -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 */ |
|||
@ -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 <expValue.h> |
|||
#include <identList.h> |
|||
|
|||
/* 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_ */ |
|||
@ -0,0 +1,29 @@ |
|||
#ifndef _IDENT_LIST_H_ |
|||
#define _IDENT_LIST_H_ |
|||
|
|||
typedef struct identList s_identList; |
|||
|
|||
#include <ident.h> |
|||
#include <expValue.h> |
|||
|
|||
/* 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_ */ |
|||
@ -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 <stmtQueue.h> |
|||
#include <block.h> |
|||
|
|||
/* |
|||
* 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_ */ |
|||
@ -0,0 +1,22 @@ |
|||
#ifndef _STMT_QUEUE_H_ |
|||
#define _STMT_QUEUE_H_ |
|||
|
|||
#include <ident.h> |
|||
|
|||
typedef struct stmtQueue s_stmtQueue; |
|||
|
|||
#include <statement.h> |
|||
|
|||
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_ */ |
|||
@ -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__ */ |
|||
@ -0,0 +1,11 @@ |
|||
#ifndef _VARIABLE_H_ |
|||
#define _VARIABLE_H_ |
|||
|
|||
#include <ident.h> |
|||
#include <expValue.h> |
|||
#include <block.h> |
|||
|
|||
s_ident * getVariable (s_block *, char *); |
|||
s_ident * getArray (s_ident *, s_expVal *); |
|||
|
|||
#endif /* _VARIABLE_H_ */ |
|||
@ -0,0 +1,101 @@ |
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" |
|||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
|||
<html xmlns="http://www.w3.org/1999/xhtml"> |
|||
<head> |
|||
<title>Test Page for Apache Installation</title> |
|||
</head> |
|||
|
|||
<body> |
|||
<p>If you can see this, it means that the installation of the <a |
|||
href="http://www.apache.org/foundation/preFAQ.html">Apache web server</a> |
|||
software on this system was successful. You may now add content to this |
|||
directory and replace this page.</p> |
|||
|
|||
<hr style="width: <# 100 #>%; height: 3px;" /> |
|||
|
|||
<h2 style="text-align: center">Seeing this instead of the website you expected?</h2> |
|||
|
|||
<# "[Ausdruck 5 + 5] " + (5 + 5) + eol #> |
|||
|
|||
<# if (! 'HALLO' == 'HALLO'): #> |
|||
<p>This page is here because the site administrator has changed the |
|||
configuration of this web server. Please <strong>contact the person |
|||
responsible for maintaining this server with questions.</strong> |
|||
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.</p> |
|||
<# 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; |
|||
#> |
|||
|
|||
<hr style="width: 100%; height: 3px;" /> |
|||
|
|||
<# repeat (hoho count=100) #> |
|||
<p>The Apache documentation is available |
|||
<a href="http://httpd.apache.org/docs-2.0/">online</a> or has been installed |
|||
<a href="/manual/">locally</a>.</p> |
|||
|
|||
<# foreach (jokus as key, val): #> |
|||
<p>You are free to use the image below on an Apache-powered web |
|||
server. Thanks for using Apache!</p> |
|||
<# end #> |
|||
|
|||
<div style="text-align: center"><img src="apache_pb.gif" alt="" /></div> |
|||
</body> |
|||
</html> |
|||
@ -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 |
|||
@ -0,0 +1,24 @@ |
|||
#include <stdio.h> |
|||
#include <malloc.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include <expValue.h> |
|||
#include <ident.h> |
|||
#include <assign.h> |
|||
#include <tepal.h> |
|||
|
|||
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; |
|||
} |
|||
@ -0,0 +1,411 @@ |
|||
/* |
|||
* bbTree (balanced binary tree) |
|||
*/ |
|||
#include <malloc.h> |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
#include <helper.h> |
|||
#include <bbtree.h> |
|||
|
|||
|
|||
/* |
|||
* 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; |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
#include <identList.h> |
|||
#include <stmtQueue.h> |
|||
|
|||
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; |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <malloc.h> |
|||
#include <string.h> |
|||
|
|||
#include <expValue.h> |
|||
#include <cast.h> |
|||
|
|||
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; |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
|
|||
#include <expValue.h> |
|||
#include <tepal_pars.h> |
|||
#include <evalCond.h> |
|||
|
|||
|
|||
/* |
|||
* 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); |
|||
} |
|||
} |
|||
@ -0,0 +1,145 @@ |
|||
#include <malloc.h> |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
|
|||
#include <expValue.h> |
|||
#include <tepal.h> |
|||
#include <tepal_pars.h> |
|||
#include <evalExpr.h> |
|||
|
|||
|
|||
/* |
|||
* 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); |
|||
} |
|||
} |
|||
@ -0,0 +1,150 @@ |
|||
#include <string.h> |
|||
#include <malloc.h> |
|||
#include <stdio.h> |
|||
|
|||
#include <expValue.h> |
|||
|
|||
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; |
|||
} |
|||
@ -0,0 +1,217 @@ |
|||
#include <string.h> |
|||
#include <malloc.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include <expValue.h> |
|||
#include <identList.h> |
|||
#include <tepal.h> |
|||
#include <ident.h> |
|||
|
|||
|
|||
/* |
|||
* 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; |
|||
} |
|||
@ -0,0 +1,238 @@ |
|||
#include <string.h> |
|||
#include <malloc.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include <expValue.h> |
|||
#include <bbtree.h> |
|||
#include <ident.h> |
|||
#include <identList.h> |
|||
|
|||
|
|||
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; |
|||
} |
|||
@ -0,0 +1,460 @@ |
|||
#include <malloc.h> |
|||
#include <stdio.h> |
|||
|
|||
#include <expValue.h> |
|||
#include <ident.h> |
|||
#include <evalExpr.h> |
|||
#include <evalCond.h> |
|||
#include <variable.h> |
|||
#include <assign.h> |
|||
#include <cast.h> |
|||
#include <tepal_pars.h> |
|||
#include <block.h> |
|||
|
|||
#include <statement.h> |
|||
|
|||
/* |
|||
* Deklaration und Definition |
|||
*/ |
|||
#include <stmtQueue.h> |
|||
|
|||
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); |
|||
} |
|||
} |
|||
@ -0,0 +1,127 @@ |
|||
#include <malloc.h> |
|||
#include <string.h> |
|||
|
|||
#include <ident.h> |
|||
#include <statement.h> |
|||
#include <block.h> |
|||
|
|||
#include <stmtQueue.h> |
|||
|
|||
/* 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; |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include <malloc.h> |
|||
#include <stdlib.h> |
|||
#include <stdarg.h> |
|||
|
|||
#include <tepal_pars.h> |
|||
#include <expValue.h> |
|||
#include <ident.h> |
|||
#include <tepal.h> |
|||
|
|||
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); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,575 @@ |
|||
%{ |
|||
#include <malloc.h> |
|||
#include <string.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include <tepal.h> |
|||
#include <evalCond.h> |
|||
#include <evalExpr.h> |
|||
#include <ident.h> |
|||
#include <identList.h> |
|||
#include <expValue.h> |
|||
#include <assign.h> |
|||
#include <variable.h> |
|||
#include <cast.h> |
|||
#include <stmtQueue.h> |
|||
#include <statement.h> |
|||
|
|||
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 <cPtr> IDENT |
|||
%token <cPtr> HTML |
|||
%token <iVal> INT |
|||
%token <fVal> FLOAT |
|||
%token <cPtr> STRING |
|||
%token <cPtr> 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 <stmt> assig; |
|||
%type <stmt> ident; |
|||
%type <stmt> cond; |
|||
%type <stmt> comp; |
|||
%type <stmt> expr; |
|||
%type <stmt> html; |
|||
%type <stmt> block_stmt; |
|||
%type <stmt> gdecl_block; |
|||
%type <stmt> simple_stmt; |
|||
%type <stmt> if_stmt; |
|||
%type <stmt> rep_stmt; |
|||
%type <stmt> fore_stmt; |
|||
%type <stmt> stmt; |
|||
%type <sQue> stmt_queue; |
|||
%type <sQue> block_queue; |
|||
%type <sQue> 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); |
|||
} |
|||
@ -0,0 +1,295 @@ |
|||
%{ |
|||
#include <malloc.h> |
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include <tepal_pars.h> |
|||
%} |
|||
|
|||
%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; |
|||
} |
|||
|
|||
<TOK>{E_TOK}\n? { |
|||
BEGIN (INITIAL); |
|||
|
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] STMT_END {#>\\n?}\n"); |
|||
#endif |
|||
|
|||
return STMT_END; |
|||
} |
|||
|
|||
<TOK>{OPERATOR} { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] %c\n", yytext[0]); |
|||
#endif |
|||
yylval.iVal = yytext[0]; |
|||
return yytext[0]; |
|||
} |
|||
|
|||
<TOK>== { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] EQ\n"); |
|||
#endif |
|||
|
|||
return EQ; |
|||
} |
|||
<TOK>!= { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] NE\n"); |
|||
#endif |
|||
|
|||
return NE; |
|||
} |
|||
<TOK>\< { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] EQ\n"); |
|||
#endif |
|||
|
|||
return LT; |
|||
} |
|||
<TOK>\> { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] EQ\n"); |
|||
#endif |
|||
|
|||
return GT; |
|||
} |
|||
<TOK>\<= { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] EQ\n"); |
|||
#endif |
|||
|
|||
return LE; |
|||
} |
|||
<TOK>\>= { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] EQ\n"); |
|||
#endif |
|||
|
|||
return GE; |
|||
} |
|||
|
|||
<TOK>&& { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] LOGAND\n"); |
|||
#endif |
|||
|
|||
return LOGAND; |
|||
} |
|||
<TOK>\|\| { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] LOGOR\n"); |
|||
#endif |
|||
|
|||
return LOGOR; |
|||
} |
|||
|
|||
<TOK>{INT} { |
|||
yylval.iVal = atol (yytext); |
|||
|
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] INT\n"); |
|||
#endif |
|||
|
|||
return INT; |
|||
} |
|||
|
|||
<TOK>{FLOAT} { |
|||
yylval.fVal = atof (yytext); |
|||
|
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] FLOAT\n"); |
|||
#endif |
|||
|
|||
return FLOAT; |
|||
} |
|||
|
|||
<TOK>{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; |
|||
} |
|||
|
|||
<TOK>repeat { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] REPEAT\n"); |
|||
#endif |
|||
|
|||
return REPEAT; |
|||
} |
|||
<TOK>count { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] COUNT\n"); |
|||
#endif |
|||
|
|||
return COUNT; |
|||
} |
|||
|
|||
<TOK>foreach { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] FOREACH\n"); |
|||
#endif |
|||
|
|||
return FOREACH; |
|||
} |
|||
<TOK>as { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] AS\n"); |
|||
#endif |
|||
|
|||
return AS; |
|||
} |
|||
|
|||
<TOK>if { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] IF\n"); |
|||
#endif |
|||
|
|||
return IF; |
|||
} |
|||
<TOK>else { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] ELSE\n"); |
|||
#endif |
|||
|
|||
return ELSE; |
|||
} |
|||
|
|||
<TOK>end { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] BLOCK_END\n"); |
|||
#endif |
|||
|
|||
return BLOCK_END; |
|||
} |
|||
|
|||
<TOK>unset { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] UNSET\n"); |
|||
#endif |
|||
|
|||
return UNSET; |
|||
} |
|||
|
|||
<TOK>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; |
|||
} |
|||
|
|||
<TOK>parent { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] PARENT\n"); |
|||
#endif |
|||
|
|||
return PARENT; |
|||
} |
|||
|
|||
<TOK>global { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] GLOBAL\n"); |
|||
#endif |
|||
|
|||
return GLOBAL; |
|||
} |
|||
|
|||
<TOK>{ICAST} { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] ICAST\n"); |
|||
#endif |
|||
|
|||
return ICAST; |
|||
} |
|||
<TOK>{FCAST} { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] FCAST\n"); |
|||
#endif |
|||
|
|||
return FCAST; |
|||
} |
|||
<TOK>{SCAST} { |
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] SCAST\n"); |
|||
#endif |
|||
|
|||
return SCAST; |
|||
} |
|||
|
|||
<TOK>{IDENT} { |
|||
yylval.cPtr = (char *) malloc (strlen (yytext) + 1); |
|||
strcpy (yylval.cPtr, yytext); |
|||
|
|||
#ifdef DEBUG |
|||
printf ("[TOKEN] IDENT\n"); |
|||
#endif |
|||
|
|||
return IDENT; |
|||
} |
|||
|
|||
<TOK>[ \t\r\n] { /* eat tokens */ } |
|||
@ -0,0 +1,56 @@ |
|||
#include <stdio.h> |
|||
#include <malloc.h> |
|||
|
|||
#include <ident.h> |
|||
#include <expValue.h> |
|||
#include <variable.h> |
|||
#include <identList.h> |
|||
|
|||
|
|||
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; |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue