// ruri - ruri language compiler
// Copyright 2000 Tom Rothamel <tom-ruri@onegeek.org>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  

// This is a program that generates another program. As an exemption,
// the output file does not need to be placed under the GPL, provided
// that the following paragraph is placed in the generated output. Please
// note that this is not an authorization to modify this program to cause
// it to output more of itself in order to circumvent my copyright.
//
// 	This program contains code Copyright 2000 Tom Rothamel.
//	It is provided without warranty, and may be redistributed 
//	and used in modified or unmodified form, provided this 
//	copyright notice is retained in the source code.

// -*-c++-*-

#ifndef PARSE_H
#define PARSE_H

#include <stdio.h>
#include <string>
#include <vector>

// Utility Functions /////////////////////////////////////////////////////////

extern FILE *of;

void iprint(char *);
void iprint(char *, int);
void iprint(char *, string);
void iprint(char *, char *, int, char *);
void iprint(string);

void cprint(char *);
void cprint(string);

void stprint(char *);
void stprint(string);

void ilabel(char *, int, char *);
void ilabel(string);

void wspace();
string operator + (string, int);

string escape(const char *);

// Expressions ///////////////////////////////////////////////////////////////

class Expr;
typedef vector<Expr *> EXV;

enum {
	EXPR_POP,
	EXPR_ADD,
	EXPR_SUB,
	EXPR_SHL,
	EXPR_OR,
	EXPR_AND,
	EXPR_NOT,
	EXPR_MUL,
	EXPR_DUP,
	EXPR_FETCH,
	EXPR_AFETCH,
	EXPR_STORE,
	EXPR_ASTORE,
	EXPR_CONST,
	EXPR_NAMEDCONST,
	EXPR_METHOD,
	EXPR_ALLOCA
};

class EAdd;

class Expr {
 protected:
	int rtti;
	EXV exprs;

	void dupify();
	virtual Expr *dupsrc();
	virtual bool candup();

	virtual int equal(Expr *);	
	virtual int condare(Expr *);

	virtual void sort(string *);
	virtual string *name();

	virtual bool trykos(string);

protected:
	int lineno;
	
 public:
	// The difference between these two is that code() decides if it
	// wants to generate the code, while gencode() always does. This
	// allows the generated expressions to decide what really needs
	// to be generated.

	// Also, gencode leaves a value on the stack, code doesn't.

	virtual void code();
	virtual void gencode();
	bool optimize(string *);
	virtual string text() = 0;

	virtual string *kosname();
	virtual void didkos();
	
	Expr();
	virtual ~Expr();

	friend class EDup;
	friend class EFetch;
	friend class EAdd;
	friend class ESub;
	friend class EConst;
	friend class ENamedConst;
	friend class EMethod;
	friend class EIn;
	friend class EMul;
	friend class EShl;
	friend class EAStore;
	friend class EAFetch;
};

class EDup : public Expr {
	Expr *src;

 protected:
	Expr *dupsrc();
	int condare(Expr *);

 public:
	void code();
	void gencode();
	string text();
	EDup(Expr *);

};

class EFetch : public Expr {
	string var;
	bool takefs;
	bool keeponstack;
	
 protected:
	string *name();
	int equal(Expr *);
	bool trykos(string);
	
 public:
	string *kosname();
	void didkos();

	void code();
	void gencode();
	string text();
	EFetch(string);
};

class EAdd : public Expr {
 protected:
	void sort(string *);

 public:	
	void code();
	void gencode();
	void addterm(Expr *);
	string text();
	EAdd(Expr *, Expr *);
};

class ESub : public Expr {
 public:
	void code();
	void gencode();

	string text();
	ESub(Expr *, Expr *);
};

class EOr : public Expr {
public:
	void code();
	void gencode();
	string text();
	EOr(Expr *, Expr *);
};


class EAnd : public Expr {
public:
	void code();
	void gencode();
	string text();
	EAnd(Expr *, Expr *);
};

class ENot : public Expr {
 public:
	void code();
	void gencode();
	string text();
	ENot(Expr *);
};

class EStore : public Expr {
	string var;
	bool keep;
	
 protected:
	bool candup();
	int equal(Expr *b);
	
 public:
	string *kosname();
	void didkos();
	void code();
	void gencode();
	string text();
	EStore(string, Expr *);
};

class EConst : public Expr {
	int val;

 protected:
	int equal(Expr *);
	
 public:
	void code();
	void gencode();
	string text();
	EConst(int);
};

class ENamedConst : public Expr {
	string name;

 protected:
	int equal(Expr *);
	
 public:
	void code();
	void gencode();
	string text();
	ENamedConst(string);
};

class EMethod : public Expr {
	string name;

 protected:
	int equal();
	bool candup();
	
 public:
	void code();
	void gencode();
	string text();
	EMethod(string, EXV *);
};

class EIn : public Expr {

 protected:
	bool candup();

 public:	
	void code();
	void gencode();
	string text();
};


class EMul : public Expr {
	int reps;

 protected:
	int equal(Expr *);

 public:
	void code();
	void gencode();
	string text();
	EMul(Expr *, int);
};

class EShl : public Expr {
	int reps;

 protected:
	int equal(Expr *);

 public:
	void code();
	void gencode();
	string text();
	EShl(Expr *, int);
};

class EPop : public Expr {
public:
	void code();
	void gencode();
	string text();
	EPop();
};

class EAFetch : public Expr {
	Expr *base;
	Expr *index;
 protected:
	int equal(Expr *);

 public:
	void code();
	void gencode();
	string text();
	EAFetch(Expr *, Expr *);
	~EAFetch();
};

class EAStore : public Expr {
	Expr *base;
	Expr *index;
	Expr *data;

 private:
	int equal(Expr *);
	
 public:
	void code();
	void gencode();
	string text();
	EAStore(Expr *, Expr *, Expr *);
	~EAStore();
};

class EAlloca : public Expr {
	Expr *expr;

public:
	void code();
	void gencode();
	string text();
	EAlloca(Expr *);
	~EAlloca();
};

class EAString : public Expr {
	string str;

public:
	void code();
	void gencode();
	string text();
	EAString(string);
};

// Condition Expressions ////////////////////////////////////////////////////

int cnum();

class Condition {
 protected:
	int true_num;
	int false_num;

 public:
	virtual void code() = 0;
	virtual string text() = 0;
	
	virtual bool alwaystrue();
	virtual bool alwaysfalse();

	virtual void settrue(int);
	virtual void setfalse(int);

	virtual bool codeinverse(int, int);
	
	Condition();
};

class CTrue : public Condition {

public:
	bool alwaystrue();
	void code();
	bool codeinverse(int, int);
	string text();
};

class CFalse : public Condition {

public:
	bool alwaysfalse();
	void code();
	bool codeinverse(int, int);
	string text();
};

class CLt : public Condition {
	Expr *e0;
	Expr *e1;

 public:
	void code();
	bool codeinverse(int, int);
	string text();
	CLt(Expr *, Expr *);
	~CLt();
};

class CGt : public Condition {
	Expr *e0;
	Expr *e1;

 public:
	void code();
	string text();
	bool codeinverse(int, int);
	CGt(Expr *, Expr *);
	~CGt();
};

class CEq : public Condition {
	Expr *e0;
	Expr *e1;

 public:
	void code();
	bool codeinverse(int, int);
	string text();
	CEq(Expr *, Expr *);
	~CEq();
};

class CAnd : public Condition {
	Condition *c1;
	Condition *c2;

public:
	void code();
	string text();
	CAnd(Condition *, Condition *);
	~CAnd();
};

class COr : public Condition {
	Condition *c1;
	Condition *c2;

public:
	void code();
	string text();
	COr(Condition *, Condition *);
	~COr();
};

class CNot : public Condition {
	Condition *cond;

public:
	void code();
	string text();
	bool alwaystrue();
	bool alwaysfalse();
	CNot(Condition *);
	~CNot();
};
	
class CExpr : public Condition {
	Expr *e;

public:
	void code();
	bool codeinverse(int, int);
	string text();
	CExpr(Expr *);
	~CExpr();
};

// Statements ////////////////////////////////////////////////////////////////

class Statement {
	int lineno;
	
public:
	virtual void code() = 0;
	virtual ~Statement() {}
	virtual string *kosname();
	virtual void didkos();
	virtual bool optimize(string *);

	Statement();
	void error(char *);
};

typedef vector<Statement *> VS;
typedef VS::iterator VSi;

class SList : public Statement {
	VS vs;

 public:
	void code();
	void add(Statement *);
	SList();
	~SList();
};

class SExprRaw : public Statement {
	Expr *expr;

 public:	
	string *kosname();
	void didkos();
	bool optimize(string *);
	void code();
	SExprRaw(Expr *);
	~SExprRaw();
};

class SExpr : public Statement {
 protected:
	Expr *expr;
	bool needdup;
	void gencode();
	
 public:	
	string *kosname();
	void didkos();
	bool optimize(string *);

	SExpr();
	~SExpr();
};

class SOut : public SExpr {
 public:
	void code();
	SOut(Expr *);
};

class SPush : public SExpr {
public:
	void code();
	SPush(Expr *);
};

class SReturn : public SExpr {
 public:
	string *kosname();
	void code();
	SReturn(Expr *);
};

class SIf : public Statement {
	Condition *cond;
	Statement *state;
	
 public:
	void code();
	SIf(Condition *, Statement *);
	~SIf();
};

class SIfElse : public Statement {
	Condition *cond;
	Statement *state;
	Statement *elst;
	
 public:
	void code();
	SIfElse(Condition *, Statement *, Statement *);
	~SIfElse();
};

class SWhile : public Statement {
	Condition *cond;
	Statement *st;

public:
	void code();
	SWhile(Condition *, Statement *);
	~SWhile();
};

class SContinue : public Statement {
public:
	void code();
};

class SBreak : public Statement {
public:
	void code();
};

class SFor : public SExpr {
	// expr = pre-loop expression
	Condition *cond; // Loop condition.
	Expr *repexpr; // Repetition expression.
	Statement *st;

public:
	string *kosname();
	void code();
	SFor(Expr *, Condition *, Expr *, Statement *);
	~SFor();
};

class SLabel : public Statement {
	string name;

public:
	void code();
	SLabel(string);
};

class SGoto : public Statement {
	string name;
public:
	void code();
	SGoto(string);
};

class SAsm : public Statement {
	string asmi;

public:
	void code();
	SAsm(string);
};

class SOutString : public Statement {
	string str;

public:
	void code();
	SOutString(string);
};

#endif
