Script Interpreter

jkallup

Erfahrenes Mitglied
Habe folgendes Prog ramm,
allerdings habe ich Probleme mit der Auswertung von if else endif anweisungen:

Code:
//#include "stdafx.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <malloc.h>

#include <iostream> folg
#include <list>
#include <queue>
using namespace std;

#define TOK_NUMBER 200
#define TOK_ID 201
#define TOK_FILE 202
#define TOK_IF 203
#define TOK_ELSE 204
#define TOK_ENDIF 205
#define TOK_PRINT 206

#define TT_EXPR 100

FILE *finput;
int lineno = 1;
int tokentype = 0;
char token_buffer[2048];
char numvalstr[256];
double numval;

int endif_counter = 0;
int if_counter = 0;

void error(char *msg);
int lex(void);
char *handle_string(void);
int handle_if(void);
char *handle_string(void);
void handle_print(void);

class listenelement {
public:
	int a_type;
    char *val_name;
	char *val_str;
	double val_expr;

    listenelement *next;

	listenelement(void);
    void datenSetzen(char *datenneu); 
    listenelement *einfuegen(char *datenneu, double v);
	listenelement *suchen(char *name);
    void ausgeben();
};

listenelement *listenAnfang = NULL;
listenelement *listenEnde = NULL;

listenelement::listenelement(void)
{
		next = NULL;
		val_expr = 0.00;
}

// --------------------
// die Zeichenkette in das Element schreiben
// --------------------
void listenelement::datenSetzen(char *datenneu) {
	val_name = (char*) malloc(2048);
    strcpy(val_name,datenneu);
}

//
// neues Element am Ende der Liste einfügen
//
listenelement *listenelement::einfuegen(char *datenneu, double v)
{	
	//char buffer[256];
	// --------------------------
    // ein neues Element einfügen
	// ---------------------------
    next = new listenelement;
	next->val_name = new char[strlen(datenneu)+1];
	next->a_type = TT_EXPR;
	next->val_expr = v;
	strcpy(next->val_name,datenneu);

	return next;
}

listenelement *listenelement::suchen(char *name)
{
	if (next != 0)
	{
		if (!strcmp(next->val_name,name))
		return next;
		next->suchen(name);
	}
	//return NULL;
}

//Alle Elemente der Liste ausgeben
void listenelement::ausgeben()
{
	if (next != 0) {
		//printf("->%s: %f\n",next->val_name, next->val_expr);
		next->ausgeben();
	}
}



class exec_stack
{
	int a[20];
	int tos; // Top of Stack
public:
	exec_stack(void);
	void push(int);
	int pop();
	int isempty(void);
	int isfull(void);
};

     exec_stack::exec_stack(void) { tos = true; } //Initialize Top of Stack
int  exec_stack::isempty   (void) { return (tos==0?1:0); }
int  exec_stack::isfull    (void) { return (tos==20?1:0); }
void exec_stack::push(int i)
{
	if(!isfull())
	{
		a[tos]=i;
		tos++;
	}
	else
	{
		printf("Stack overflow error !\nPossible Data Loss !");
	}
}

int exec_stack::pop()
{
	if(!isempty())
	{
		return(a[--tos]);
	}
	else
	{
		printf("Stack is empty! What to pop...!");
	}
	return 0;
}


exec_stack *ex_stack = NULL;

void emit(int t, double tval)
{
	switch (t)
	{
		case '+': case '-': case '*': case '/':
			printf("%c",t);
		break;
		case TOK_NUMBER:
			printf("%f",numval);
		break;
		case TOK_ID:
			printf("%s",token_buffer);
		break;
	}
}

void factor(void)
{
	int c;
	c = lex();
	switch (c)
	{
		case '(':
		{
			c = lex();
			if (c == TOK_NUMBER)
			{
				c = lex();
				if (c == ')')
				{
					break;
				}
			}
		}
		break;

		case TOK_NUMBER:
			emit(TOK_NUMBER,numval);
		break;
	}
}

/*
void term(void)
{
}

void rxpr(void)
{
	c = lex();
	term();
	if (c == TOK_NUMBER)
	{

	}
}*/

int skip_white_space (void)
{
  int c;
  int inside;

  c = getc (finput);

  for (;;)
    {
      int cplus_comment;

      switch (c)
	  {
	    case '/':
	  /* FIXME: Should probably be merged with copy_comment.  */
	  c = getc (finput);
	  if (c != '*' && c != '/')
	    {
	      printf("unexpected `/' found and ignored");
	      break;
	    }
	  cplus_comment = (c == '/');

	  c = getc (finput);

	  inside = 1;
	  while (inside)
	    {
	      if (!cplus_comment && c == '*')
		{
		  while (c == '*')
		    c = getc (finput);

		  if (c == '/')
		    {
		      inside = 0;
		      c = getc (finput);
		    }
		}
	      else if (c == '\n')
		{
		  lineno++;
		  if (cplus_comment)
		    inside = 0;
		  c = getc (finput);
		}
	      else if (c == EOF)
		  {
			printf("unterminated comment");
			exit(1);
		  }
	      else
		c = getc (finput);
	    }

	  break;

	case '\n':
	  lineno++;

	case ' ':
	case '\t':
	case '\f':
	  c = getc (finput);
	  break;

	default:
	  return c;
	}
  }
}

int lex(void)
{
	int c;
	c = skip_white_space();

	switch (c)
	{
		case EOF:
		return EOF;

		case 'A':    case 'B':    case 'C':    case 'D':    case 'E':
		case 'F':    case 'G':    case 'H':    case 'I':    case 'J':
		case 'K':    case 'L':    case 'M':    case 'N':    case 'O':
		case 'P':    case 'Q':    case 'R':    case 'S':    case 'T':
		case 'U':    case 'V':    case 'W':    case 'X':    case 'Y':
		case 'Z':
		case 'a':    case 'b':    case 'c':    case 'd':    case 'e':
		case 'f':    case 'g':    case 'h':    case 'i':    case 'j':
		case 'k':    case 'l':    case 'm':    case 'n':    case 'o':
		case 'p':    case 'q':    case 'r':    case 's':    case 't':
		case 'u':    case 'v':    case 'w':    case 'x':    case 'y':
		case 'z':
	    case '_':

		strcpy(token_buffer,"");

		while (isalnum (c) || c == '_' || c == '.')
		{
			char buffer[5];
			sprintf(buffer,"%c",c);
			strcat(token_buffer,buffer);
			c = getc (finput);
		}

		     if (strcmp(token_buffer,strlwr("file")) == 0) return TOK_FILE;
		else if (strcmp(token_buffer,strlwr("exit")) == 0) return 33;
		else if (strcmp(token_buffer,strlwr("if")) == 0)  { endif_counter++; return TOK_IF; }
		else if (strcmp(token_buffer,strlwr("else")) == 0) return TOK_ELSE;
		else if (strcmp(token_buffer,strlwr("endif")) == 0) {
			endif_counter--;
			return TOK_ENDIF;
		}
		else	return TOK_ID;

		break;

		case '?':
			return TOK_PRINT;
		break;

		case '0':    case '1':    case '2':    case '3':    case '4':
		case '5':    case '6':    case '7':    case '8':    case '9':
		case '.':
		{
			strcpy(numvalstr,"");

			while (isdigit (c) || c == '.')
			{
				char buffer[5];
				sprintf(buffer,"%c",c);
				strcat(numvalstr,buffer);
				c = getc (finput);
			}
			numval = atof(numvalstr);
			return TOK_NUMBER;
		}
		break;

		case '"': return '"';
		break;
	}
	return -1;
}


void stmt(void)
{
	char s[2048];
	int c, r;
	static int if_chk = 0;
	for (;;)
	{
		c = lex();
		if (c == EOF) exit(0);
		else if (c == TOK_ELSE) return;
		else if (c == TOK_IF)
		{
			if_label:
			if_chk++;
			r = handle_if();
			if (r == 1) {
				stmt();
			}
			else {
				do {
					c = lex();
				} while (c != TOK_ELSE  &&
					 c != TOK_ENDIF &&
					 c != TOK_IF &&
					 c != EOF);

				if (c == TOK_IF)
				{
					goto if_label;
				}

				if (c == TOK_ELSE)
				{
					stmt();
					return;		
				}
				else if (c == TOK_ENDIF)
				{
					--if_chk;
					cout << "chk: " << if_chk << " , ";
					//if (if_chk <= 0)
					{
						cout << "nuller" << endl;
						return;
					}
				}		
			}
		}
		else if (c == TOK_ID)
		{
			strcpy(s,token_buffer);
			c = skip_white_space();
			if (c == '=')
			{
				c = lex();
				if (c == TOK_NUMBER)
				{
					listenEnde = listenAnfang;
					listenEnde = listenEnde->einfuegen(s,numval);
				}
			}
			free(s);
		}
		else if (c == TOK_PRINT)
		{
			handle_print();
		}
	}
}

char *handle_string(void)
{
	char *str = (char*) malloc(2048);
	int c;
	int pos = 0;

	for (;;)
		{
		c = getc(finput);
		if (c == '"') break; else
		if (c == '\\') {
			c = getc(finput);
			if (c == 't') str[pos++] = '\t'; else
			if (c == 'n') str[pos++] = '\n'; else str[pos++] = c;
		} else
		str[pos++] = c;
	}	str[pos] = '\0';

	c = skip_white_space();
	if (c == '+')
	{
		for (;;)
		{
			c = skip_white_space();

			if (c == EOF) break;
			if (c == TOK_NUMBER)
			{
			}
			else if (c == '"')
			{
				strcat(str,handle_string());
			}
			else {
				ungetc(c,finput);
				return str;
			}

			c = lex();

			if (c == TOK_ID)
			{
				char cs[256];

				listenEnde = listenAnfang;
				listenEnde = listenEnde->suchen(token_buffer);

				if (listenEnde == NULL) {
					listenEnde = new listenelement;
					printf("new list\n");
				}
				if (listenEnde->a_type == TT_EXPR)
				{
					sprintf(cs,"%f",listenEnde->val_expr);
					strcat(str,cs);
				}
			} 
		}
	}
	else ungetc(c,finput);

	return str;
}

void error(char *msg)
{
	printf("Zeile: %d: %s\n",lineno,msg);
	exit(1);
}

void handle_print(void)
{
	char *str = (char*) malloc(2048);
	int c;
	c = skip_white_space();
	if (c == '"')
	{
		strcpy(str,handle_string());
		{
			printf("erg: %s",str);
			//ex_stack->push(false);
		}
		free(str);
	}
}

int handle_if(void)
{
	double vs1, vs2;
	int c, r1 = 0;

	c = lex();
	if (c == TOK_ID)
	{
		listenEnde = listenAnfang;
		listenEnde = listenEnde->suchen(token_buffer);

		vs1 = listenEnde->val_expr;

	} else if (c == TOK_NUMBER)	{
		vs1 = numval;
	}

	c = skip_white_space();
	if (c == '=')
	{
		c = lex();
		if (c == TOK_NUMBER)
		{
			vs2 = numval;
			r1 = vs1 == vs2;
		}
	}
	return r1;
}

int main(int argc, char **argv)
{
	listenAnfang = new listenelement;
	listenEnde = new listenelement;
	
	listenAnfang->datenSetzen("Element 0");
	listenEnde = listenAnfang;

	finput = stdin;
	lineno = 1;

	stmt();
}





huer der script code:

Code:
init = 1

if init = 1

 eins_var = 4.12
 var2 = 3.142

if var2 = 3.142
  ? "ist ok\n"
  ? "12345\n"
  if var2 = 4.3
    ? "vier = vier\n"
  else
    ? "nicht"
    if var2 = 43
      ? "wieder ok\n"
      if var2 = 10
	? "ten10\n"
      else
        ? "nicht 10\n"	
      endif
      ? "returner\n"
    else
      ? "nein\n"
    endif
    ? "1234567890\n"
    ? "dumdidum\n"
  endif
  ? "exit "
else
  ? "lucky\n"
  ? "dupi\n"
endif

? "back to the roots\n"


endif

für hilfe bin ich dankbar
jkallup
 
Hallo,

im Prinzip habe ich Probleme eine IF ELSE ENDIF verschachtelung zu interpretieren.
Frage mich aber auch, wie man einen AST Programmiert (kann auch eine C++ Klasse sein) und wie man sich da dann durchschlingelt.

mfg
jkallup

wäre net wenn das mal einer in c++ einfach aufzeigt.
 
Hi.

Ein if-Statement besteht aus einer Bedinung und dem auszuführenden Code und (optional) einem else Code-Teil.

C:
struct if_stmt {
  cond_expr* cond;
  code* body;
  code* else;
};
Du baust dementsprechend den AST in der Art zusammen und mußt beim Interpretieren nur prüfen ob die Bedingung wahr ist und den Code ausführen, oder evtl. den else-Code ausführen.

Gruß
 
an welcher stelle muss ich code einfügen, um aus der "run" schleife zu springen, um anderen code abarbeiten - also feststellen, wenn ELSE oder ENDIF erreicht wurde ...: http://codepad.org/5iAabv6H ?

Code:
#include <ast_code.h>
#include <ast_if.h>
#include <iostream>
using namespace std;

print_stmt::print_stmt(void)
{
}

std::string print_stmt::operator << (std::string str)
{
	text += str;
	cout << "string: " << text << endl;
	return text;
}


if_stmt::if_stmt(void)
{
	exec_true = NULL;
	exec_else = NULL;
}

code_stmt::code_stmt(void)
{
	if_found = NULL;
	print_cmd = NULL;
}

void code_stmt::run(void)
{
	if (next != NULL)
	{
		if (if_found != NULL)
		{
			if (if_found->cond == true)	{
				if_found->exec_true = new code_stmt;
				if_found->exec_true->pass = 20;
				if_found->exec_true->run();
			}
		}

		if (print_cmd != NULL)
		{
			cout << print_cmd->text << endl;
			next->run();
		}
		std::cout << "code: " << pass << endl;
	}
}

void code_stmt::add(print_stmt p)
{
	next = new code_stmt;
	next->print_cmd = &p;
}

int main(int argc, char **argv)
{
	class code_stmt *root = new code_stmt;
	
	class print_stmt print1; print1 << "Hallo Welt!";
	class print_stmt print2; print2 << "Heute war es gut";
	class print_stmt print3; print3 << "glubsch";

	root->add(print1);
	root->add(print2);
	
	root->if_found = new if_stmt;
	root->if_found->cond = true;
	root->if_found->exec_true = new code_stmt;
	root->if_found->exec_true->add(print3);

	root->pass = 10;
	root->run();
	delete root;
	return 0;
}




#ifndef IF_STMT_HEADER
#define IF_STMT_HEADER

#include <ast_code.h>

class if_stmt
{
public:
	if_stmt(void);

	bool cond;
	class code_stmt *exec_true;
	class code_stmt *exec_else;
};

#endif



#include <iostream>
#include <ast_if.h>

class print_stmt
{
public:
	std::string text;

	print_stmt(void);
	std::string operator << (std::string);
};

class code_stmt
{
public:
	code_stmt(void);
	void run(void);
	void add(print_stmt	p);

	class if_stmt		*if_found;
	class print_stmt	*print_cmd;
	int pass;

	class code_stmt *next;
};

#endif
 
Hi.

Dein Skript besteht aus einer Folge von Anweisungen. Du müßtest lediglich aus der run() Methode zurückspringen wenn die letzte Anweisung des if / else Zweigs beendet ist.
C++:
class script {
  stmt_t *stmts;
public:
  void run() {
    for (...) { // für jede Anweisung
      stmt.run();
    }
};

class if_stmt : public stmt_t {
  ...
public:
  void run() {
    if (cond->eval()) {
      body->run();
    } else if (else_block != 0) {
      else_block->run();
    }
};
Außerdem ist es vermutlich keine gute Idee die Bedingung eines if als ein bool Attribut abzubilden, da die Bedingung von den Werten der Variablen abhängt, welche sich schließlich ändern können...

Gruß
 
Zurück