Browse Source

Initial repository layout

master
Georg Hopp 19 years ago
commit
41f4765afb
  1. 1
      AUTHORS
  2. 60
      ChangeLog
  3. 9
      Makefile.am
  4. 0
      NEWS
  5. 21
      README
  6. 63
      TODO
  7. 25
      autoclean.sh
  8. 10
      autogen.sh
  9. 46
      configure.ac
  10. 6
      include/Makefile.am
  11. 9
      include/assign.h
  12. 66
      include/bbtree.h
  13. 18
      include/block.h
  14. 10
      include/cast.h
  15. 9
      include/evalCond.h
  16. 15
      include/evalExpr.h
  17. 31
      include/expValue.h
  18. 7
      include/helper.h
  19. 35
      include/ident.h
  20. 29
      include/identList.h
  21. 74
      include/statement.h
  22. 22
      include/stmtQueue.h
  23. 14
      include/tepal.h
  24. 11
      include/variable.h
  25. 101
      index.tpl
  26. 25
      src/Makefile.am
  27. 24
      src/assign.c
  28. 411
      src/bbtree.c
  29. 82
      src/block.c
  30. 30
      src/cast.c
  31. 113
      src/evalCond.c
  32. 145
      src/evalExpr.c
  33. 150
      src/expValue.c
  34. 217
      src/ident.c
  35. 238
      src/identList.c
  36. 460
      src/statement.c
  37. 127
      src/stmtQueue.c
  38. 65
      src/tepal.c
  39. 575
      src/tepal_pars.y
  40. 295
      src/tepal_scan.l
  41. 56
      src/variable.c

1
AUTHORS

@ -0,0 +1 @@
Georg Steffers <georg@steffers.org>

60
ChangeLog

@ -0,0 +1,60 @@
0.0.1: First test with a bison grammar and flex scanner. Process simple
statement as in the examples contained in the bison docs.
0.0.2: more work on grammar (add loops and conditionals, experiments),
also add tplparser.[ch] that serves for general purpose grammer
actions.
0.0.3: brought the grammar to a more or less final state.
Add several functions for procession different expressions.
Add variables.
Do some leak checking.
0.0.4: Finalize variables with adding support for arrays and hashes.
A word to variables:
- There is no need to declare a variable. As soon as one assigns
something to an identifier, that identifier holds that value.
- It is an error to use a variable that has no assigned value
within an expression.
- Assigning a new value to a variable simply overwrites its
previous content. There is no way to recover the previous
content.
- The above is also true if the variable was an array or hash.
- Variables can be of type INT, FLOAT or STRING. If you use
Variables or values of different type within an expression
implicit casts are done. For rules of implicit casts see below.
- There is actually no way to explicitly cast a variable, but that
may change in future.
- Rules for implicit casts are:
* normally the first operand of an expression specifies the
resulting type. All following operands are implicitly cast to
the type of the first operand.
* The only exception to this is if one of the operands is a
sting. Then all other operands are implicitly cast to string.
Again do some leak and memchecks.
0.0.5: implement explicit casts
put all things in a sane autobuild package.
called the whole thing: tepal "TEpal is a template PArsing Library"
0.0.6: 25/11/2006 lots of code cleanups to prepare to code to use AST
all expressions have now an own datatype. That reduces the grammar
file a lot (and makes it easier to keep it conflict-free) because
i do not need to distinguish between int, float and string in the
grammar right now.
Also expression computation has become much cleaned.
I also change the behaviour of freeing data. No function frees
any of it calling parameters. This results in a lot of
memory leaks right now. !!!IMPORTANT!!! That has to be fixed soon!
---
Already fixed some leaks, but some still remain.
26/11/2006 more leaks resolved
well, right now no leaks remain when i use tepal with my test
index.html
---
If an undefined variable is used an error message is given.
!!!FIXME!!! I need a way to maintain the complete variable identifier
to tell it with the error message.
0.0.7: AST implemented
a very big step is done. An ast is implemented. Everything works as
before, but right now to demontrate the functionality of the ast also
if statements are computed correctly.

9
Makefile.am

@ -0,0 +1,9 @@
DEFS = -DHAS_CONFIG @DEFS@
nobase_include_HEADERS = index.tpl
ACLOCAL_AMFLAGS = -I m4
# EXTRA_DIST =
SUBDIRS = src include

0
NEWS

21
README

@ -0,0 +1,21 @@
tepal is a Template Parsing Library, written in C.
It's origin lies in my unhappieness with PHP, JSP and other
languages designed for web-development. Lately i learned a little
about template system and worked a little with smarty and after a
while i got the idea that if one wants to seperate program logic
from display logic it is also possible to write you application
in C as i prefer. The FastCGI interface is as fast or even faster than
the PHP interface. The only thing needed is a library that does the
same things as smarty, set template variables, parse a template and
write the result.
Well, it turns out that this only thing was more work than i first
thought, especially because i never wrote an interpreter or compiler
before. And i had not college courses on that issue too. So i had to
find out everything by my own. Thanks go to the excellent documentation
of flex and bison and the Telos GmbH that published a simple interpreter.
While i was writing this I recognised that it might be usefull at other
things too. Everything that can be created by a cleartext template
and some application logic can be created with this lib.

63
TODO

@ -0,0 +1,63 @@
for version 0.0.*
- implement blocks
* every block has to have its own identifier list. Additional
a reference to to the upper block should be part of a block
to realize variable lookup in upper blocks.
* every block contains a statement list, that hold all statements
that occured within the block.
* a block is as itself a statement, that could be part of a statement
list.
* blocklocal, global and parent variables
variables in general are block local. This means, using varable a
within a sub-block does not affect an existing variable a within a
parent block.
Every block can contain one optional globals declaration section. This
is a special block, wich declares identifiers to be used as global
(topmost block) identifiers. If a non-existent identifier is deklared
in such a section a global variable is created.
Additionally there will be a _parent_ operator for use with an identifier.
This will allow one to access a variable used (and therefor deklared)
somewhere above the local block. If no variable with this identifier can
be found an error message is shown and processing will stop.
- implement loops and conditionals
* first the statement directly following the loop or conditional
tokens is saved.
* the this is executed 0..n times depending on the loop or conditional.
- ich habe herausgefunden das alle Ausdrücken in denen Variablen vorkommen
auch in einen statement stack aufgenommen werden müssen. Nur konstante
Ausdrücken können direkt ausgewertet werden und muessen nicht in
den AST (abstract statement tree, ist faktisch aber eher ein stack da
jeder branch unmittelbar ausgeführt wird). Ups, sorry this is
accidently german.
- Add an interface to access the variable space of the interpreter from
within a C program in an easy way.
- add CGI-lib for parsing of requests.
- write a first test-webapp.
- code cleanups
- comment the code more completely.
- date Datentyp hinzufügen
- Modifizierer für das Ausgabeformat hinzufügen.
=> we come to version 0.1.0
=========================================================================
for version 0.1.*
- implement Sessions
* How to work with cookies?
* Sessionvariables will be saves within a BerkDB.
- maybe begin of an application-server, that preserves the state of an
application between its calls via cgi.
- allow and implement includes within templates.

25
autoclean.sh

@ -0,0 +1,25 @@
#!/bin/sh
# Script for cleaning all autogenerated files.
test ! -f Makefile || make distclean
# Generated by aclocal.
rm -f aclocal.m4
# Generated by autoconf.
rm -f configure
# Generated by autoheader
rm -f config.h.in
# Generated or brought in by automake.
rm -f Makefile.in
rm -f src/Makefile.in
rm -f include/Makefile.in
rm -f INSTALL
rm -f COPYING
# Generated by all in config
rm -rf config
rm -rf autom4te.cache

10
autogen.sh

@ -0,0 +1,10 @@
#!/bin/sh
# Script for regenerating all autogenerated files.
mkdir config
aclocal
autoconf
autoheader
libtoolize -c -f
automake -a -c

46
configure.ac

@ -0,0 +1,46 @@
AC_PREREQ(2.59)
AC_INIT(tepal, 0.0.7, georg@steffers.org)
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_SRCDIR([src/tepal.c])
AC_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE
AC_CANONICAL_HOST
# Checks for programs.
AC_PROG_CC
AC_PROG_MAKE_SET
AC_LIBTOOL_WIN32_DLL
AC_PROG_LIBTOOL
AC_PROG_YACC
AC_PROG_LEX
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([libintl.h locale.h stdlib.h string.h unistd.h wchar.h])
# Checks for libraries.
AC_MSG_CHECKING([for Win32])
case "$host" in
*-*-mingw*)
win32="yes, use windows threads"
;;
*)
win32="no"
;;
esac
AC_MSG_RESULT([$win32])
AM_CONDITIONAL(WIN32, test "x$win32" != "xno")
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
# Checks for library functions.
AC_CHECK_FUNCS([memset setlocale])
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([src/Makefile])
AC_CONFIG_FILES([include/Makefile])
AC_OUTPUT

6
include/Makefile.am

@ -0,0 +1,6 @@
nobase_include_HEADERS = tepal.h helper.h \
evalExpr.h evalCond.h expValue.h \
ident.h identList.h bbtree.h \
variable.h assign.h cast.h \
statement.h stmtQueue.h block.h

9
include/assign.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_ */

66
include/bbtree.h

@ -0,0 +1,66 @@
#ifndef _BBTREE_H_
#define _BBTREE_H_
/* this is only here for testing. In final version
* it should be in bbtree.c */
typedef
struct bbTreeNode
{
void * value;
long height;
struct bbTreeNode * left;
struct bbTreeNode * right;
} s_bbTreeNode;
#define BBTREE_LEFT_HEIGHT(t) ((t)->left ? (t)->left->height : -1)
#define BBTREE_RIGHT_HEIGHT(t) ((t)->right ? (t)->right->height : -1)
#define BBTREE_AVL(t) (BBTREE_RIGHT_HEIGHT ((t)) - \
BBTREE_LEFT_HEIGHT ((t)))
/*
* comparison for tree-node values.
* Has to be defined by user and set
* with bbTreeNew.
*
* params:
* left: pointer to left value
* right: pointer to right value
*
* returns:
* 0: if values equal
* 1: if right greater left
* -1: if left greater right
*/
typedef int (* t_bbTreeCmp) (void *, void *);
typedef
struct bbTree
{
struct bbTreeNode * root;
t_bbTreeCmp cmp;
} s_bbTree;
/* constructor, destructor */
s_bbTree * bbTreeNew (t_bbTreeCmp);
void bbTreeFree (s_bbTree *);
/* data manipulation */
void * bbTreeInsert (s_bbTree *, void *);
void * bbTreeSeek (s_bbTree *, void *);
void * bbTreeRemove (s_bbTree *, void *);
/* analysation */
void * bbTreeMin (s_bbTree *);
void * bbTreeMax (s_bbTree *);
int bbTreeSize (s_bbTree *);
/* bbTree to other Datastructure */
void ** bbTreeInOrder (s_bbTree *, void **);
#endif /* _BBTREE_H_ */

18
include/block.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_ */

10
include/cast.h

@ -0,0 +1,10 @@
#ifndef _CAST_H_
#define _CAST_H_
#include "expValue.h"
s_expVal * castExprToInt (s_expVal *);
s_expVal * castExprToFloat (s_expVal *);
s_expVal * castExprToString (s_expVal *);
#endif /* _CAST_H_ */

9
include/evalCond.h

@ -0,0 +1,9 @@
#ifndef _EVALCOND_H_
#define _EVALCOND_H_
#include "expValue.h"
int evalCondExpr (s_expVal *);
int evalComp (int, s_expVal *, s_expVal *);
#endif /* _EVALCOND_H_ */

15
include/evalExpr.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_ */

31
include/expValue.h

@ -0,0 +1,31 @@
#ifndef _EXP_VALUE_H_
#define _EXP_VALUE_H_
#define EXP_TYP_INT 'i'
#define EXP_TYP_FLOAT 'f'
#define EXP_TYP_STRING 's'
/* Typdeklaration, etc */
typedef struct expVal s_expVal;
/* Constructoren / Destructoren */
s_expVal * expValueIntNew (long);
s_expVal * expValueFloatNew (double);
s_expVal * expValueStringNew (char *);
s_expVal * expValueClone (s_expVal *);
void expValueFree (s_expVal *);
/* Accessors */
long expValueInt (s_expVal *);
double expValueFloat (s_expVal *);
char * expValueString (s_expVal *);
/* analyse expValue */
int expValueGetType (s_expVal *);
#endif /* _EXP_VALUE_H_ */

7
include/helper.h

@ -0,0 +1,7 @@
#ifndef _HELPER_H_
#define _HELPER_H_
#define ABS(a) ((a)<0 ? -(a) : (a))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif /* _HELPER_H */

35
include/ident.h

@ -0,0 +1,35 @@
#ifndef _IDENT_H_
#define _IDENT_H_
#define ID_TYP_UNDEF 'n'
#define ID_TYP_EXP 'e'
#define ID_TYP_IDL 'L'
struct ident;
typedef struct ident s_ident;
#include <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_ */

29
include/identList.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_ */

74
include/statement.h

@ -0,0 +1,74 @@
#ifndef _STMT_H_
#define _STMT_H_
#define STMT_CONST 0
#define STMT_BLOCK 1
#define STMT_PRINT 10
#define STMT_IF 11
#define STMT_FOREACH 12
#define STMT_REPEAT 13
#define STMT_ASSIGN 14
#define STMT_UNSET 15
#define STMT_EVAL_PLUS 20
#define STMT_EVAL_MINUS 21
#define STMT_EVAL_TIMES 22
#define STMT_EVAL_OVER 23
#define STMT_EVAL_MODULO 24
#define STMT_EVAL_NEG 25
#define STMT_IDENT_VAR 30
#define STMT_IDENT_ARRAY 31
#define STMT_IDENT_VAL 32
#define STMT_CAST_INT 40
#define STMT_CAST_FLOAT 41
#define STMT_CAST_STRING 42
#define STMT_COMP_EQ 50
#define STMT_COMP_NE 51
#define STMT_COMP_LT 52
#define STMT_COMP_GT 53
#define STMT_COMP_LE 54
#define STMT_COMP_GE 55
#define STMT_COND_EXPR 60
#define STMT_COND_AND 61
#define STMT_COND_OR 62
#define STMT_COND_NEG 63
#define STYP_NONE 0
#define STYP_COND 1
#define STYP_EVAL 2
#define STYP_IDVAL 3
/*
* Deklaration und Definition
*/
union stmtType
{
int cond;
struct expVal * eVal;
struct ident * idVal;
};
typedef struct stmt s_stmt;
typedef union stmtType u_stmtType;
#include <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_ */

22
include/stmtQueue.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_ */

14
include/tepal.h

@ -0,0 +1,14 @@
#ifndef __HTMLPARS_H__
#define __HTMLPARS_H__
#include "expValue.h"
#define ERR_UNDEF_VAR 0
#define ERR_NO_INDEX 1
#define ERR_STRING_OPERATOR 2
#define ERR_FLOAT_OPERATOR 3
void exitError (int, ...);
void printExpr (s_expVal *);
#endif /* __HTMLPARS_H__ */

11
include/variable.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_ */

101
index.tpl

@ -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>

25
src/Makefile.am

@ -0,0 +1,25 @@
tepal_source = tepal.c tepal_pars.c tepal_scan.c \
evalExpr.c evalCond.c expValue.c \
variable.c assign.c cast.c \
ident.c identList.c bbtree.c \
statement.c stmtQueue.c block.c
nobase_include_HEADERS = tepal_pars.y tepal_scan.l
BUILT_SOURCES = tepal_pars.c tepal_scan.c
CLEANFILES = tepal_pars.c tepal_scan.c ../include/tepal_pars.h
bin_PROGRAMS = tepal
tepal_SOURCES = $(tepal_source)
tepal_CFLAGS = -I../include
tepal_pars.c: Makefile tepal_pars.y
$(YACC) -d tepal_pars.y
mv y.tab.c tepal_pars.c
mv y.tab.h ../include/tepal_pars.h
tepal_scan.c: Makefile tepal_scan.l
$(LEX) tepal_scan.l
mv lex.yy.c tepal_scan.c

24
src/assign.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;
}

411
src/bbtree.c

@ -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;
}

82
src/block.c

@ -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;
}

30
src/cast.c

@ -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;
}

113
src/evalCond.c

@ -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);
}
}

145
src/evalExpr.c

@ -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);
}
}

150
src/expValue.c

@ -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;
}

217
src/ident.c

@ -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;
}

238
src/identList.c

@ -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;
}

460
src/statement.c

@ -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);
}
}

127
src/stmtQueue.c

@ -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;
}

65
src/tepal.c

@ -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);
}
}
}

575
src/tepal_pars.y

@ -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);
}

295
src/tepal_scan.l

@ -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 */ }

56
src/variable.c

@ -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;
}
Loading…
Cancel
Save