948 lines
25 KiB
C
948 lines
25 KiB
C
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <sys/stat.h>
|
|||
|
#include <sys/types.h>
|
|||
|
#include <sys/socket.h>
|
|||
|
#include <arpa/inet.h>
|
|||
|
#include <fcntl.h>
|
|||
|
#include <string.h>
|
|||
|
#include "botforth.h"
|
|||
|
|
|||
|
// CDB-Krempel
|
|||
|
extern void cdb_startup();
|
|||
|
|
|||
|
// Berkeley-DB-Krempel
|
|||
|
extern void bdb_init();
|
|||
|
|
|||
|
int infoblock_get_accesslevel(struct vector *word)
|
|||
|
{
|
|||
|
struct vector *infoblock;
|
|||
|
assert(word);
|
|||
|
infoblock = word->head->content;
|
|||
|
return *(int *) infoblock->head->content;
|
|||
|
}
|
|||
|
|
|||
|
void infoblock_set_accesslevel(struct vector *word, int al)
|
|||
|
{
|
|||
|
struct vector *infoblock;
|
|||
|
assert(word);
|
|||
|
infoblock = word->head->content;
|
|||
|
*(int *) infoblock->head->content = al;
|
|||
|
}
|
|||
|
|
|||
|
char *infoblock_get_name(struct vector *word)
|
|||
|
{
|
|||
|
struct vector *infoblock;
|
|||
|
assert(word);
|
|||
|
infoblock = word->head->content;
|
|||
|
return infoblock->head->next->content;
|
|||
|
}
|
|||
|
|
|||
|
void infoblock_set_name(struct vector *word, char *name)
|
|||
|
{
|
|||
|
struct vector *infoblock;
|
|||
|
assert(word);
|
|||
|
infoblock = word->head->content;
|
|||
|
// problem hier
|
|||
|
//(char*)infoblock->head->next->content=name;
|
|||
|
infoblock->head->next->content = name;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* welchen typ hat ein string in wirklichkeit? int? float? string?
|
|||
|
*/
|
|||
|
int get_stringtype(char *s)
|
|||
|
{
|
|||
|
int z = 0; // zustand
|
|||
|
unsigned i;
|
|||
|
char c; // aktuelles zeichen
|
|||
|
int ret = -1;
|
|||
|
for (i = 0; i <= strlen(s); i++) {
|
|||
|
c = s[i];
|
|||
|
switch (z) {
|
|||
|
case 0:
|
|||
|
if (c == '\0') // schon zuende, pech gehat
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
if (c == '-' || c == '+')
|
|||
|
z = 1; // ein vorzeichen
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 2; // eine zahl beginnt
|
|||
|
if (z == 0) // nichts gefunden? schade.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
break;
|
|||
|
case 1: // Vorzeichen
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 2; // eine zahl beginnt
|
|||
|
if (z == 1 && ret == -1) // nichts gefunden? schade.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
break;
|
|||
|
case 2: // Zahl nach Vorzeichen
|
|||
|
z = 0;
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 2; // die zahl geht weiter, gut.
|
|||
|
if (c == '\0') // zuende? gut, int erkannt.
|
|||
|
ret = BF_TYPE_INT;
|
|||
|
if (c == '.')
|
|||
|
z = 17; // koennte floating-point sein.
|
|||
|
if (c == 'e' || c == 'E')
|
|||
|
z = 19; // exponent von floating-point zahl
|
|||
|
if (z == 0 && ret == -1) // nichts gefunden? schade.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
break;
|
|||
|
case 17: // floating-point, direkt nach dem .
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 18; // ist wohl doch noch ne ziffer, prima.
|
|||
|
if (c == 'e' || c == 'E')
|
|||
|
z = 19; // exponent erkannt
|
|||
|
if (c == '\0') // schon vorbei? das reicht nicht.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
if (z == 17 && ret == -1) // nichts gefunden? schade.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
break;
|
|||
|
case 18: // ziffern nach dem .
|
|||
|
z = 0;
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 18; // ist wohl doch noch ne ziffer, prima.
|
|||
|
if (c == 'e' || c == 'E')
|
|||
|
z = 19; // exponent erkannt
|
|||
|
if (c == '\0')
|
|||
|
ret = BF_TYPE_FLOAT; // prima, float erkannt
|
|||
|
if (z == 0 && ret == -1) // nichts gefunden? schade.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
break;
|
|||
|
case 19: // floating-point: e
|
|||
|
z = 0; // wenns sonst nichts ist, ists ein string
|
|||
|
if (c == '+' || c == '-')
|
|||
|
z = 20; // ein vorzeichen
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 21; // schoen, eine ziffer
|
|||
|
if (z == 0) // nichts gefunden? schade.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
break;
|
|||
|
case 20: // floating-point: vorzeichen nach e
|
|||
|
z = 0; // wie immer, wenns sonst nix ist, ists ein string
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 21; // schoen, eine ziffer
|
|||
|
if (z == 0 && ret == -1) // nichts gefunden? schade.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
break;
|
|||
|
case 21: // floating-point: ziffern nach e
|
|||
|
z = 0; // wenns sonst nichts ist, ists ein befehl
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 21; // gut, noch immer eine ziffer
|
|||
|
if (c == '\0')
|
|||
|
ret = BF_TYPE_FLOAT;
|
|||
|
if (z == 0 && ret == -1) // nichts gefunden? schade.
|
|||
|
ret = BF_TYPE_STRING;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (ret > -1) {
|
|||
|
return ret;
|
|||
|
}
|
|||
|
}
|
|||
|
return BF_TYPE_STRING;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Lexikalische Analyse eines botforth-programms
|
|||
|
*
|
|||
|
* progstring: Das Programm als String
|
|||
|
*
|
|||
|
* return: vector, der die einzelnen Symbole des Programms enth<EFBFBD>lt
|
|||
|
*/
|
|||
|
struct vector *botforth_parse(char *progstring)
|
|||
|
{
|
|||
|
struct vector *program = vector_create();
|
|||
|
struct vector *infoblock = vector_create();
|
|||
|
int lineend(char c) {
|
|||
|
if (c == '\r' || c == '\n' || c == '\0')
|
|||
|
return 1;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
int whitespace(char c) {
|
|||
|
if (c == ' ' || c == '\t' || lineend(c))
|
|||
|
return 1;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
void addsymbol(char *progstring, int *first, int last, int type) {
|
|||
|
struct node *symb = 0;
|
|||
|
char *item;
|
|||
|
int itemlen;
|
|||
|
int *i;
|
|||
|
float *f;
|
|||
|
printf("neues Symbol\n");
|
|||
|
itemlen = last - (*first) + 1;
|
|||
|
//assert(itemlen>0);
|
|||
|
item = malloc(itemlen + 1);
|
|||
|
assert(item != 0);
|
|||
|
strncpy(item, progstring + (*first) - 1, itemlen);
|
|||
|
item[itemlen] = 0;
|
|||
|
//printf("Symbol erkannt: %s (%i)\n",item,type);
|
|||
|
switch (type) {
|
|||
|
case BF_TYPE_STRING:
|
|||
|
case BF_TYPE_C_TEXT:
|
|||
|
symb = node_create(item, type);
|
|||
|
break;
|
|||
|
case BF_TYPE_INT:
|
|||
|
i = malloc(sizeof(int));
|
|||
|
*i = atoi(item);
|
|||
|
symb = node_create(i, type);
|
|||
|
free(item);
|
|||
|
break;
|
|||
|
case BF_TYPE_FLOAT:
|
|||
|
f = malloc(sizeof(float));
|
|||
|
*f = atof(item);
|
|||
|
symb = node_create(f, type);
|
|||
|
free(item);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
vector_push(program, symb);
|
|||
|
*first = last + 1;
|
|||
|
}
|
|||
|
int z = 0; // Zustand
|
|||
|
char c; // Aktuelles Zeichen
|
|||
|
unsigned i;
|
|||
|
int first;
|
|||
|
char item[255];
|
|||
|
char *temps;
|
|||
|
int *tempi;
|
|||
|
struct node *tempn;
|
|||
|
int temp;
|
|||
|
// create infoblock
|
|||
|
tempi = malloc(sizeof(int));
|
|||
|
*tempi = 99;
|
|||
|
tempn = node_create(tempi, BF_TYPE_INT);
|
|||
|
vector_put(infoblock, "accesslevel", tempn);
|
|||
|
temps = malloc(7);
|
|||
|
sprintf(temps, "noname");
|
|||
|
tempn = node_create(temps, BF_TYPE_STRING);
|
|||
|
vector_put(infoblock, "name", tempn);
|
|||
|
tempi = malloc(sizeof(int));
|
|||
|
*tempi = 0;
|
|||
|
tempn = node_create(tempi, BF_TYPE_INT);
|
|||
|
vector_put(infoblock, "clearcache", tempn);
|
|||
|
// add program infoblock to the programm
|
|||
|
vector_put_vector(program, "infoblock", infoblock);
|
|||
|
printf("start parser\n");
|
|||
|
strcpy(item, "");
|
|||
|
first = 1;
|
|||
|
for (i = 0; i <= strlen(progstring); i++) {
|
|||
|
c = progstring[i];
|
|||
|
switch (z) {
|
|||
|
case 0:
|
|||
|
z = 2; // wenns sonst nix ist, ists ein Befehl
|
|||
|
if ((c >= '0') && (c <= '9')) // Vermutlich Zahl, oder Befehl
|
|||
|
z = 1;
|
|||
|
if (((c >= 'a') && (c <= 'z')) || // Befehl
|
|||
|
(c == '.'))
|
|||
|
z = 2;
|
|||
|
if ((c == '+') || (c == '-')) // Vorzeichen einer Zahl oder Befehl
|
|||
|
z = 4;
|
|||
|
if (c == '"') // Zeichenkette
|
|||
|
z = 5;
|
|||
|
if (c == '{') // Befehlszeiger
|
|||
|
z = 6;
|
|||
|
if (whitespace(c)) // Leerzeichen ist nix
|
|||
|
z = 0;
|
|||
|
if (c == '/') // Kommentar-Beginn oder Befehl
|
|||
|
z = 8;
|
|||
|
if (c == '$') // Variable lesen
|
|||
|
z = 12;
|
|||
|
if (c == '!') // Variable schreiben
|
|||
|
z = 14;
|
|||
|
break;
|
|||
|
case 1: // Zahl
|
|||
|
// davon ausgehen, dass es ein befehl wird
|
|||
|
z = 2;
|
|||
|
if ((c >= '0') && (c <= '9'))
|
|||
|
z = 1; // bleibt eine zahl
|
|||
|
if (c == '.')
|
|||
|
z = 17; // koennte floating-point sein.
|
|||
|
if (c == 'e' || c == 'E')
|
|||
|
z = 19; // exponent von floating-point zahl
|
|||
|
if (whitespace(c)) {
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_INT);
|
|||
|
z = 0; // zahl fertig erkannt
|
|||
|
}
|
|||
|
break;
|
|||
|
case 2: // Befehl
|
|||
|
if (whitespace(c)) {
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_C_TEXT);
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 3: // Zeichenkette
|
|||
|
if (c == '"') {
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_STRING);
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 4: // Vorzeichen
|
|||
|
// wenns sonst nichts ist, ists ein Befehl
|
|||
|
z = 2;
|
|||
|
if ((c >= 'a') && (c <= 'z')) // Befehl
|
|||
|
z = 2;
|
|||
|
if ((c >= '0') && (c <= '9')) // Zahl (mit Vorzeichen) oder Befehl
|
|||
|
z = 1;
|
|||
|
if (whitespace(c)) { // Befehl erkannt
|
|||
|
z = 0;
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_C_TEXT);
|
|||
|
}
|
|||
|
break;
|
|||
|
case 5: // f<>hrendes " einer Zeichenkette
|
|||
|
// Zeichenkette vielleicht sofort schon wieder zuende?
|
|||
|
if (c == '"') {
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_STRING);
|
|||
|
z = 0;
|
|||
|
} else
|
|||
|
z = 3;
|
|||
|
break;
|
|||
|
case 6: // F<>hrendes { eines Befehlszeigers
|
|||
|
z = 7;
|
|||
|
break;
|
|||
|
case 7: // Befehlszeiger
|
|||
|
if (c == '}') {
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_C_TEXT);
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 8: // Kommentar-Beginn
|
|||
|
if (c == '*') {
|
|||
|
z = 9; // Ja, wirklich ein Kommentar-Beginn, also weitermachen
|
|||
|
first++;
|
|||
|
} else if (c == '/') { // ein Zeilenkommentar
|
|||
|
z = 11;
|
|||
|
first++;
|
|||
|
} else if (whitespace(c)) {
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_C_TEXT);
|
|||
|
z = 0;
|
|||
|
} else
|
|||
|
z = 2;
|
|||
|
break;
|
|||
|
case 9: // Im Kommentar
|
|||
|
first++;
|
|||
|
if (c == '*')
|
|||
|
z = 10; // Vielleicht h<>rt der Kommentar ja nun auf...
|
|||
|
break;
|
|||
|
case 10: // Kommentar-Ende
|
|||
|
first++;
|
|||
|
if (c == '/')
|
|||
|
z = 0;
|
|||
|
else
|
|||
|
z = 9;
|
|||
|
break;
|
|||
|
case 11: // Zeilenkommentar
|
|||
|
first++;
|
|||
|
if (lineend(c)) {
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 12: // Variable lesen, $-Zeichen
|
|||
|
z = 13;
|
|||
|
first++;
|
|||
|
break;
|
|||
|
case 13: // Variable lesen, Variablenname
|
|||
|
if (whitespace(c)) {
|
|||
|
temp = 1;
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_STRING);
|
|||
|
addsymbol("$", &temp, 1, BF_TYPE_C_TEXT);
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 14: // Variable schreiben, !-Zeichen
|
|||
|
if (c == '=') {
|
|||
|
// koennte sich um != statt um ne variable handeln...
|
|||
|
z = 16;
|
|||
|
} else if (whitespace(c) || c == '=') {
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_C_TEXT);
|
|||
|
z = 0;
|
|||
|
} else {
|
|||
|
z = 15;
|
|||
|
first++;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 15: // Variable schreiben, Variablenname
|
|||
|
if (whitespace(c)) {
|
|||
|
temp = 1;
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_STRING);
|
|||
|
addsymbol("!", &temp, 1, BF_TYPE_C_TEXT);
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 16: // womoeglich != statt einem Variablen-schreiben
|
|||
|
if (whitespace(c)) {
|
|||
|
addsymbol(progstring, &first, i,
|
|||
|
BF_TYPE_C_TEXT);
|
|||
|
z = 0;
|
|||
|
} else {
|
|||
|
z = 15; // wohl doch nur ein Variablen-lesen, wo aber ein = im Variablenname ist...
|
|||
|
}
|
|||
|
break;
|
|||
|
case 17: // floating-point, direkt nach dem .
|
|||
|
z = 2; // wenns sonst nichts ist, ists ein befehl
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 18; // ist wohl doch noch ne ziffer, prima.
|
|||
|
if (c == 'e' || c == 'E')
|
|||
|
z = 19; // exponent erkannt
|
|||
|
if (whitespace(c)) { // leerzeichen direkt nach .? kann nur befehl sein
|
|||
|
addsymbol(progstring, &first, i, BF_TYPE_C_TEXT); // befehl
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
case 18: // ziffern nach dem .
|
|||
|
z = 2; // wenns sonst nichts ist, ists ein befehl
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 18; // ist wohl doch noch ne ziffer, prima.
|
|||
|
if (c == 'e' || c == 'E')
|
|||
|
z = 19; // exponent erkannt
|
|||
|
if (whitespace(c)) {
|
|||
|
addsymbol(progstring, &first, i, BF_TYPE_FLOAT); // prima, float erkannt
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 19: // floating-point: e
|
|||
|
z = 2; // wenns sonst nichts ist, ists ein befehl
|
|||
|
if (c == '+' || c == '-')
|
|||
|
z = 20; // ein vorzeichen
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 21; // schoen, eine ziffer
|
|||
|
if (whitespace(c)) { // leerzeichen direkt nach e? kann nur befehl sein
|
|||
|
addsymbol(progstring, &first, i, BF_TYPE_C_TEXT); // befehl
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 20: // floating-point: vorzeichen nach e
|
|||
|
z = 2; // wie immer, wenns sonst nix ist, ists ein befehl
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 21; // schoen, eine ziffer
|
|||
|
if (whitespace(c)) { // leerzeichen direkt nach vorzeichen? kann nur befehl sein
|
|||
|
addsymbol(progstring, &first, i, BF_TYPE_C_TEXT); // befehl
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
case 21: // floating-point: ziffern nach e
|
|||
|
z = 2; // wenns sonst nichts ist, ists ein befehl
|
|||
|
if (c >= '0' && c <= '9')
|
|||
|
z = 21; // gut, noch immer eine ziffer
|
|||
|
if (whitespace(c)) {
|
|||
|
addsymbol(progstring, &first, i, BF_TYPE_FLOAT); // prima, float erkannt
|
|||
|
z = 0;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
if ((z == 0) || (z == 5) || (z == 6))
|
|||
|
first++;
|
|||
|
}
|
|||
|
return program;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
struct vector *word_load(char *name, char *ns)
|
|||
|
{
|
|||
|
char *word;
|
|||
|
char *buffer, *buffer2;
|
|||
|
char *tmpns;
|
|||
|
struct vector *program;
|
|||
|
struct node *lex;
|
|||
|
int newaccesslevel;
|
|||
|
int *tempint;
|
|||
|
struct vector *v, *infoblock;
|
|||
|
struct node *n = NULL, *n2 = NULL;
|
|||
|
// todo: ueberpruefen, ob lexicon leer ist
|
|||
|
assert(lexicon);
|
|||
|
assert(name);
|
|||
|
buffer = NULL;
|
|||
|
v = NULL;
|
|||
|
lex = lexicon->tail;
|
|||
|
do {
|
|||
|
if (buffer)
|
|||
|
free(buffer);
|
|||
|
if (ns == NULL) {
|
|||
|
// search all namespaces
|
|||
|
buffer =
|
|||
|
malloc(10 + strlen(lex->content) +
|
|||
|
strlen(name));
|
|||
|
sprintf(buffer, "command/%s/%s",
|
|||
|
(char *) lex->content, name);
|
|||
|
tmpns = lex->content;
|
|||
|
} else {
|
|||
|
// only use given namespace
|
|||
|
buffer = malloc(10 + strlen(ns) + strlen(name));
|
|||
|
sprintf(buffer, "command/%s/%s", ns, name);
|
|||
|
tmpns = ns;
|
|||
|
}
|
|||
|
printf("lade wort: %s\n", buffer);
|
|||
|
|
|||
|
// set new accesslevel depending on the name of the namespace
|
|||
|
newaccesslevel = 3;
|
|||
|
if (strcmp(tmpns, "lib") == 0)
|
|||
|
newaccesslevel = 2;
|
|||
|
if (strcmp(tmpns, "service") == 0)
|
|||
|
newaccesslevel = 2;
|
|||
|
if (strcmp(tmpns, "bot") == 0)
|
|||
|
newaccesslevel = 1;
|
|||
|
// is the word in the cache?
|
|||
|
n = vector_pick(words, buffer);
|
|||
|
if (n) {
|
|||
|
if (n->type != BF_TYPE_INT) {
|
|||
|
if (n->type == BF_TYPE_VECTOR) {
|
|||
|
v = n->content;
|
|||
|
printf
|
|||
|
("wort %s im cache gefunden\n",
|
|||
|
buffer);
|
|||
|
} else {
|
|||
|
printf
|
|||
|
("falscher typ auf dem word-cache\n");
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
} else {
|
|||
|
printf("Nur Dummy im Cache gefunden\n");
|
|||
|
}
|
|||
|
} else {
|
|||
|
printf("wort muss von platte geholt werden\n");
|
|||
|
v = load_file(buffer);
|
|||
|
if (v == NULL) {
|
|||
|
// Falls das Programm nicht gefunden wurde: Einen Dummy in den Cache legen
|
|||
|
tempint = malloc(sizeof(int));
|
|||
|
*tempint = 0;
|
|||
|
n2 = node_create(tempint, BF_TYPE_INT);
|
|||
|
vector_put(words, buffer, n2);
|
|||
|
}
|
|||
|
}
|
|||
|
lex = lex->prev;
|
|||
|
} while (v == NULL && lex != NULL && ns == NULL);
|
|||
|
if (v) { // sollte immer erfuellt sein
|
|||
|
// ist schon ein fertig kompiliertes programm enthalten?
|
|||
|
n = vector_pick(v, "program");
|
|||
|
if (n) {
|
|||
|
if (n->type == BF_TYPE_VECTOR) {
|
|||
|
printf
|
|||
|
("vorkompiliertes programm gefunden\n");
|
|||
|
program = n->content;
|
|||
|
} else {
|
|||
|
printf("cache-word ist kein vector\n");
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
} else {
|
|||
|
word = vector_pick_string(v, "inhalt");
|
|||
|
assert(word != NULL);
|
|||
|
program = botforth_parse(word);
|
|||
|
// infoblock ergaenzen
|
|||
|
infoblock =
|
|||
|
(struct vector *) program->head->content;
|
|||
|
buffer2 = malloc(strlen(buffer) + 1);
|
|||
|
sprintf(buffer2, "%s", buffer);
|
|||
|
n2 = node_create(buffer2, BF_TYPE_STRING);
|
|||
|
vector_put(infoblock, "cachename", n2);
|
|||
|
buffer2 = malloc(strlen(name) + 1);
|
|||
|
sprintf(buffer2, "%s", name);
|
|||
|
free(infoblock->head->next->content);
|
|||
|
infoblock->head->next->content = buffer2;
|
|||
|
// update accesslevel in the infoblock
|
|||
|
infoblock_set_accesslevel(program, newaccesslevel);
|
|||
|
// update program name
|
|||
|
buffer2 = malloc(strlen(name) + 1);
|
|||
|
sprintf(buffer2, "%s", name);
|
|||
|
infoblock_set_name(program, buffer2);
|
|||
|
if (program->head == NULL) {
|
|||
|
printf("leeres programm: %s\n", word);
|
|||
|
}
|
|||
|
// todo: speicherleck?
|
|||
|
if (program) {
|
|||
|
program = botforth_compile(program);
|
|||
|
if (program->head) {
|
|||
|
// todo: und was wenn nicht? speicherleck?
|
|||
|
printf
|
|||
|
("Wort im cache speichern\n");
|
|||
|
printf("name: %s\n", buffer);
|
|||
|
buffer2 = malloc(8);
|
|||
|
sprintf(buffer2, "program");
|
|||
|
vector_put_vector(v, buffer2,
|
|||
|
program);
|
|||
|
vector_replace_vector(words,
|
|||
|
buffer, v);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return program;
|
|||
|
} else {
|
|||
|
if (buffer)
|
|||
|
free(buffer);
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
void botforth_replaceword(struct vector *program)
|
|||
|
{
|
|||
|
char *cachename, *newcachename;
|
|||
|
char *shortname;
|
|||
|
struct node *n, *newn;
|
|||
|
struct node *oldcache;
|
|||
|
struct vector *oldcachecontent;
|
|||
|
struct node *newcache;
|
|||
|
struct vector *newcachecontent;
|
|||
|
struct vector *newprogram;
|
|||
|
// Programmname ermitteln
|
|||
|
cachename =
|
|||
|
(char *) ((struct vector *) program->head->content)->
|
|||
|
head->next->next->next->content;
|
|||
|
shortname =
|
|||
|
(char *) ((struct vector *) program->head->content)->
|
|||
|
head->next->content;
|
|||
|
printf("name des zu ersetzenden programs %s bzw. %s\n", cachename,
|
|||
|
shortname);
|
|||
|
// den kompletten Cache-Eintrag zu dem Programm laden
|
|||
|
oldcache = vector_get(words, cachename);
|
|||
|
oldcachecontent = (struct vector *) oldcache->content;
|
|||
|
// altes programm entfernen, aber noch im speicher belassen, wird noch
|
|||
|
// durch *program referenziert
|
|||
|
vector_get(oldcachecontent, "program");
|
|||
|
// rest des alten cacheeintrags komplett loeschen
|
|||
|
node_destroy(oldcache);
|
|||
|
newprogram = word_load(shortname, NULL);
|
|||
|
if (newprogram) {
|
|||
|
// wort existiert noch auf platte
|
|||
|
newcachename =
|
|||
|
(char *) ((struct vector *) program->head->
|
|||
|
content)->head->next->next->next->content;
|
|||
|
// word_load hat das neue wort auch in den cache geworfen
|
|||
|
newcache = vector_pick(words, newcachename);
|
|||
|
assert(newcache != NULL);
|
|||
|
newcachecontent = (struct vector *) newcache->content;
|
|||
|
// Das neue Programm aus den Cacheeintrag rausnehmen, bleibt durch
|
|||
|
// *newprogram verzeigert
|
|||
|
vector_get(newcachecontent, "program");
|
|||
|
// Das alte Programm erstmal in den neuen Cacheeintrag schieben
|
|||
|
n = node_create(program, BF_TYPE_VECTOR);
|
|||
|
// todo: irgendwas stimmt hier nicht, abstuerze an dieser stelle
|
|||
|
vector_replace(newcachecontent, "program", n);
|
|||
|
} else {
|
|||
|
// programm existiert nicht mehr auf platte. nun wenigstens
|
|||
|
// einen platzhalter anlegen
|
|||
|
// todo: das sollte man auch mal wirklich richtig machen...
|
|||
|
newprogram = vector_create();
|
|||
|
printf("programm existiert nicht mehr!\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
|
|||
|
// den _inhalt_ des alten programms manuell loeschen
|
|||
|
n = program->head;
|
|||
|
while (n) {
|
|||
|
newn = n->next;
|
|||
|
node_destroy(n);
|
|||
|
n = newn;
|
|||
|
}
|
|||
|
// Zeiger anpassen
|
|||
|
program->head = newprogram->head;
|
|||
|
program->tail = newprogram->tail;
|
|||
|
program->size = newprogram->size;
|
|||
|
}
|
|||
|
|
|||
|
void botforth_call(struct vector *program)
|
|||
|
{
|
|||
|
assert(program != NULL);
|
|||
|
// int die tiefenbegrenzung noch nicht erreicht?
|
|||
|
//if(rstack->size<50) {
|
|||
|
vector_push_node(rstack, pc);
|
|||
|
vector_push_vector(rstack, cword);
|
|||
|
vector_push_int(rstack, accesslevel);
|
|||
|
// soll das programm aus dem cache entfernt werden?
|
|||
|
if (*(int *) ((struct vector *) program->head->content)->
|
|||
|
head->next->next->content == 1) {
|
|||
|
printf("aufruf eines zu loeschenden programms\n");
|
|||
|
botforth_replaceword(program);
|
|||
|
}
|
|||
|
// set the accesslevel
|
|||
|
//printf("acceslevel: %i\n",infoblock_get_accesslevel(program));
|
|||
|
accesslevel = infoblock_get_accesslevel(program);
|
|||
|
// set the program counter to the new word
|
|||
|
pc = program->head->next;
|
|||
|
cword = program;
|
|||
|
//}
|
|||
|
}
|
|||
|
|
|||
|
void botforth_return()
|
|||
|
{
|
|||
|
int oldaccesslevel;
|
|||
|
// todo: speicherleck vielleicht irgendwie?
|
|||
|
oldaccesslevel = vector_pop_int(rstack);
|
|||
|
(void) oldaccesslevel; // Warnung unterdr<64>cken
|
|||
|
cword = vector_pop_vector(rstack);
|
|||
|
pc = vector_pop_node(rstack);
|
|||
|
if (cword)
|
|||
|
accesslevel = infoblock_get_accesslevel(cword);
|
|||
|
//printf("ruecksprung\n");
|
|||
|
}
|
|||
|
|
|||
|
void botforth_interpreter(struct vector *program, int withinfoblock)
|
|||
|
{
|
|||
|
char *command;
|
|||
|
void *temppointer;
|
|||
|
char *temp;
|
|||
|
char *temp2;
|
|||
|
int (*fpointer) (); // function pointer
|
|||
|
struct vector *newprogram; // temp var for loading new words;
|
|||
|
struct node *tempnode;
|
|||
|
struct node *c; // pointer to the actual command
|
|||
|
cword = program;
|
|||
|
pc = program->head;
|
|||
|
if (pc == NULL)
|
|||
|
return;
|
|||
|
if (withinfoblock)
|
|||
|
pc = pc->next;
|
|||
|
if (pc == NULL)
|
|||
|
return;
|
|||
|
do {
|
|||
|
printf(".");
|
|||
|
// increase the program counter and load the new word
|
|||
|
c = pc;
|
|||
|
assert(c != NULL);
|
|||
|
pc = pc->next;
|
|||
|
assert(c->content != NULL);
|
|||
|
// printf("'%s'(%i) ",node_toString(node_copy(c)),c->type);
|
|||
|
switch (c->type) {
|
|||
|
case BF_TYPE_C_TEXT: // Befehl in Textform
|
|||
|
command = c->content;
|
|||
|
//printf("textbefehl: %s\n",command);
|
|||
|
if (strlen(command) > 1 && command[0] == '_'
|
|||
|
&& command[1] != '_') {
|
|||
|
temp2 = infoblock_get_name(cword);
|
|||
|
printf("hauptfunktionsname: %s\n", temp2);
|
|||
|
temp =
|
|||
|
malloc(strlen(temp2) +
|
|||
|
strlen(command) + 1);
|
|||
|
sprintf(temp, "%s%s", temp2, command);
|
|||
|
// free(command); // temp2 muss nicht geloescht werden
|
|||
|
command = temp; // problem, wo wird command freigegeben?
|
|||
|
// unterfunktionsaufruf
|
|||
|
}
|
|||
|
temppointer = getintcommand(command);
|
|||
|
if (temppointer) {
|
|||
|
free(c->content);
|
|||
|
c->type = BF_TYPE_C_INT;
|
|||
|
c->content = temppointer;
|
|||
|
pc = c;
|
|||
|
} else {
|
|||
|
printf("neues wort laden: %s\n", command);
|
|||
|
// load and execute a word
|
|||
|
newprogram = word_load(command, NULL);
|
|||
|
printf("programm geladen: %s\n", command);
|
|||
|
if (newprogram) {
|
|||
|
// call the word
|
|||
|
botforth_call(newprogram);
|
|||
|
// change the program
|
|||
|
printf("setze externer befehl\n");
|
|||
|
free(c->content);
|
|||
|
c->content = newprogram;
|
|||
|
c->type = BF_TYPE_C_EXT;
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case BF_TYPE_C_INT: // Interner Befehl
|
|||
|
fpointer = c->content;
|
|||
|
fpointer();
|
|||
|
break;
|
|||
|
case BF_TYPE_C_EXT: // Externer Befehl
|
|||
|
//printf("externer befehl\n");
|
|||
|
if (rstack->size < 8000) {
|
|||
|
botforth_call((struct vector *)
|
|||
|
c->content);
|
|||
|
} else {
|
|||
|
printf("RSTACK UEBERGELAUFEN!\n");
|
|||
|
}
|
|||
|
break;
|
|||
|
case BF_TYPE_STRING: // String
|
|||
|
temp = malloc(strlen(c->content) + 1);
|
|||
|
sprintf(temp, "%s", (char *) c->content);
|
|||
|
tempnode = node_create(temp, c->type);
|
|||
|
vector_push(dstack, tempnode);
|
|||
|
break;
|
|||
|
case BF_TYPE_INT: // Integer
|
|||
|
case BF_TYPE_FLOAT: // Float
|
|||
|
case BF_TYPE_POINTER: // Pointer
|
|||
|
tempnode = node_copy(c);
|
|||
|
vector_push(dstack, tempnode);
|
|||
|
break;
|
|||
|
default: // Unbekannt (todo!)
|
|||
|
printf("unbekanntes symbol im programm: %i\n",
|
|||
|
c->type);
|
|||
|
exit(0);
|
|||
|
break;
|
|||
|
}
|
|||
|
// end of the word? have a look at the return stack...
|
|||
|
while ((pc == NULL && rstack->tail != NULL) ||
|
|||
|
(accesslevel > 1 && runlimit > 0
|
|||
|
&& (int) time(NULL) > runlimit)) {
|
|||
|
botforth_return();
|
|||
|
}
|
|||
|
} while (pc != NULL);
|
|||
|
printf("Interpreter ende\n");
|
|||
|
}
|
|||
|
|
|||
|
struct vector *botforth_compile(struct vector *word)
|
|||
|
{
|
|||
|
struct node *n, *newn, *cn, *newcn;
|
|||
|
char *buffer;
|
|||
|
// char *text;
|
|||
|
struct vector *compword;
|
|||
|
// struct vector *ncstack;
|
|||
|
struct vector *nword = vector_create();
|
|||
|
printf("starte compiler\n");
|
|||
|
assert(cstack != NULL);
|
|||
|
if (word == NULL)
|
|||
|
return NULL;
|
|||
|
n = word->head;
|
|||
|
while (n != NULL) {
|
|||
|
newn = n->next;
|
|||
|
if (n->type == BF_TYPE_C_TEXT) {
|
|||
|
if (getintcommand(n->content)) {
|
|||
|
// internal command
|
|||
|
// todo: hier direkt die adresse reinsetzen
|
|||
|
vector_push(nword, n);
|
|||
|
} else {
|
|||
|
// external command
|
|||
|
// save the environment to estack
|
|||
|
//vector_push_vector(estack,lexicon);
|
|||
|
vector_push_vector(estack, rstack);
|
|||
|
vector_push_node(estack, pc);
|
|||
|
vector_push_vector(estack, cword);
|
|||
|
// create a new environment
|
|||
|
//lexicon=vector_create();
|
|||
|
buffer = malloc(9);
|
|||
|
sprintf(buffer, "compiler");
|
|||
|
vector_push_string(lexicon, buffer);
|
|||
|
rstack = vector_create();
|
|||
|
// try to load the compiler-word
|
|||
|
compword =
|
|||
|
word_load(n->content, "compiler");
|
|||
|
// restore the old environment
|
|||
|
cword = vector_pop_vector(estack);
|
|||
|
pc = vector_pop_node(estack);
|
|||
|
vector_destroy(rstack);
|
|||
|
rstack = vector_pop_vector(estack);
|
|||
|
assert(rstack != NULL);
|
|||
|
/*
|
|||
|
vector_destroy(lexicon);
|
|||
|
lexicon=vector_pop_vector(estack);
|
|||
|
*/
|
|||
|
node_destroy(vector_pop(lexicon));
|
|||
|
assert(lexicon != NULL);
|
|||
|
if (compword) {
|
|||
|
assert(compword->head != NULL); // todo: das sollte weg, leere programme sind ok
|
|||
|
printf("kompiliere %s\n",
|
|||
|
(char *) n->content);
|
|||
|
// save the environment to estack
|
|||
|
assert(cstack != NULL);
|
|||
|
vector_push_vector(estack, cstack);
|
|||
|
vector_push_vector(estack, rstack);
|
|||
|
vector_push_node(estack, pc);
|
|||
|
vector_push_vector(estack, cword);
|
|||
|
// create a new environment
|
|||
|
cstack = vector_create();
|
|||
|
rstack = vector_create();
|
|||
|
// start the interpreter
|
|||
|
printf("start interpreter\n");
|
|||
|
botforth_interpreter(compword, 1);
|
|||
|
printf
|
|||
|
("den neuen teil nochmal kompilieren\n");
|
|||
|
cstack = botforth_compile(cstack);
|
|||
|
// copy the cstack to the new word
|
|||
|
printf("umkopieren\n");
|
|||
|
cn = cstack->head;
|
|||
|
while (cn) {
|
|||
|
assert(cn != NULL);
|
|||
|
newcn = cn->next;
|
|||
|
vector_push(nword, cn);
|
|||
|
//newn=cn;
|
|||
|
//vector_insert(word,n,cn);
|
|||
|
cn = newcn;
|
|||
|
}
|
|||
|
// restore the old environment
|
|||
|
cword = vector_pop_vector(estack);
|
|||
|
pc = vector_pop_node(estack);
|
|||
|
vector_destroy(rstack);
|
|||
|
rstack = vector_pop_vector(estack);
|
|||
|
assert(rstack != NULL);
|
|||
|
cstack->head = cstack->tail = NULL;
|
|||
|
vector_destroy(cstack);
|
|||
|
cstack = vector_pop_vector(estack);
|
|||
|
assert(cstack != NULL);
|
|||
|
node_destroy(n);
|
|||
|
} else {
|
|||
|
vector_push(nword, n);
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
vector_push(nword, n);
|
|||
|
}
|
|||
|
n = newn;
|
|||
|
}
|
|||
|
free(word);
|
|||
|
return nword;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int main(int argc, char **argv)
|
|||
|
{
|
|||
|
//struct vector *rstack=vector_create();
|
|||
|
struct vector *program;
|
|||
|
char *temp;
|
|||
|
int i;
|
|||
|
words = vector_create();
|
|||
|
cstack = vector_create();
|
|||
|
rstack = vector_create();
|
|||
|
dstack = vector_create();
|
|||
|
estack = vector_create();
|
|||
|
lstack = vector_create();
|
|||
|
// help stacks
|
|||
|
zstack = vector_create();
|
|||
|
var = vector_create();
|
|||
|
lexicon = vector_create();
|
|||
|
interpretcounter = 0;
|
|||
|
// zufall initialisieren
|
|||
|
srand(time(NULL));
|
|||
|
|
|||
|
cdb_startup();
|
|||
|
bdb_init();
|
|||
|
|
|||
|
// push parameters to dstack
|
|||
|
for (i = 1; i < argc; i++) {
|
|||
|
temp = malloc(strlen(argv[i]) + 1);
|
|||
|
sprintf(temp, "%s", argv[i]);
|
|||
|
vector_push_string(dstack, temp);
|
|||
|
}
|
|||
|
|
|||
|
// set lexicon
|
|||
|
//temp=malloc(5); sprintf(temp,"dope");
|
|||
|
//vector_push_string(lexicon,temp);
|
|||
|
temp = malloc(strlen("lib") + 1);
|
|||
|
sprintf(temp, "lib");
|
|||
|
vector_push_string(lexicon, temp);
|
|||
|
temp = malloc(strlen("service") + 1);
|
|||
|
sprintf(temp, "service");
|
|||
|
vector_push_string(lexicon, temp);
|
|||
|
temp = malloc(strlen("bot") + 1);
|
|||
|
sprintf(temp, "bot");
|
|||
|
vector_push_string(lexicon, temp);
|
|||
|
|
|||
|
program = word_load("main", "bot");
|
|||
|
debug(program);
|
|||
|
botforth_interpreter(program, 1);
|
|||
|
printf("Datenstapel: ");
|
|||
|
debug(dstack);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|