/*

  This is a part of the Project Frontier's Source code.

  Copyright (C) 1997-98 Francis Gastellu
                    aka Lone Runner/Aegis

  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

// PowerPPL Compiler - PPC Sources

#define YYSTYPE char*

#include <stdio.h>
#include <process.h>
#include <dir.h>
#include <io.h>
#include <string.h>
#include <alloc.h>
#include <dos.h>
#include "..\ppc\pps_tab.h"
#include "..\ppc\fortify.h"

#define MAXPROCS 409
#define MAXFUNCS 405

#define STRCONST 1
#define INTCONST 2
#define HEXCONST 3
#define SYMBOL   4
#define DBLCONST 5
#define BINCONST 6
#define OCTCONST 7

#define FUNC_IDENTIFIER 1
#define PROC_IDENTIFIER 2
#define VAR_IDENTIFIER  3

#define LOOP_WHILE  1
#define LOOP_FOR    2
#define LOOP_IF     3
#define LOOP_CASE   4
#define LOOP_ELSEIF 5

#define CODEBUFFERSTARTSIZE 131072
#define CODEBUFFERINC 65535
#define BUFFERSINC 	  128
#define BUILDINC       32
#define LABELINC       64
#define IDENTIFIERINC  32
#define LABELSTACKINC  16
#define LOOPINC		   16
#define SELECTINC       8
#define PARAMNINC	   16
#define SYMCODEINC   4096
#define FILESINC        4
#define SOURCEINC       8

#define ARGVAR 1
#define ARGIMM 2
#define ARGEXP 3
#define ARGARR 4
#define ARGNONE 5

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

typedef struct {
    char *name;
    int type;
    char nDim;
    int dim1;
    int dim2;
    int dim3;
    void *data;
    void *paramTypes;
    int external;
    long offset;
    int identHdr;
	} identListType;

typedef struct {
	char *name;
    int num;
    unsigned int offset;
    } labelType;

typedef struct {
    char *name;
    unsigned int offset;
	} gotoType;

typedef struct {
	unsigned long codeOffset;
    unsigned long sourceOffset;
    unsigned int line;
    } symType;

typedef struct {
	FILE *stream;
    unsigned int line;
    unsigned int cursource;
    } filesType;

typedef struct {
    char *name;
	int minArg;
    int maxArg;
    int argType;
    int reserved;
	}statement;

typedef struct {
	char	*name;
	short	argMini;
	short	argMaxi;
	int		nUsed;
	}function;

extern statement far stat[];
extern function far func[];
extern char far *Type[];
extern char far *reserved[];

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

int check_type(void);
int check_func(void);
void compile(char *file);
void registerIdent(char *data);
void registerIdentList(int type);
void allocMem(void);
void unallocMem(void);
void freeIdentifier(void);
int globalVarType(int type);
void checkIdentifier(void);
void sendToBuffer(void *ptr, int size);
void writePPE(void);
void writeSYM(void);
void writeLIB(void);
void registerLabel(char *name, unsigned int offset);
void registerJump(char *name, unsigned int offset);
int mkLexRet(int a, int b);
void freeBuffers(void);
char *newcode(int l);
char *lookup(int type);
char *mkFunc(int f);
char *mkStat(unsigned int s);
char *concat(char *c1, char *c2);
void initbuild(void);
void build(char *value);
char *separator(int s, int arg);
char *retreiveBuild(void);
void allocBuffers(void);
void writeLines(int line);
void processJumps(void);
void processVars(void);
void checkJumps(void);
char *newTempLabel(void);
void fakeNextLabel(char *);
void pushLabelStack(char *s);
char *popLabelStack(void);
void closeLoop(char *s, int loopType);
void checkLoop(char *s, int loopType);
void openLoop(int loopType);
void endifLoop(void);
void beep(void);
void pushSelect(char *var);
char *popSelect(void);
void switchLastLabels(void);
char *semValue(char *s);
void checkDim(char *var, int n);
char *semText(char *s);
void invalidVar(char *v);
void registerProc(char *procName, int nArgs, char *argTypes, int pf, int funcReturnType);
void checkProc(char *procName, int nArgs, char *argTypes, int pf, int funcReturnType);
void enterProc(char *procName, int type);
void leaveProc(int type);
char *zero(void);
int isHex(char c);
void treatOption(char *o);
void mkUserVariable(char *name, int type, int ndim1);
char *toVar(char *sem);
void correctAssign(void);
void analyze(char *s);
void checkFunc(int f, int npar);
void pushParamN(int n);
int popParamN(void);
int isInternal(char *name);
void registerLibVars(char *name, int libNum);
int openLib(char *name);
void insertLibCode(char *name, int libNum);
void libSize(int line, long size);
void linking(int line);
void codeSize(int line, long size);
void writecode(char *file);
void mymemcpy(char huge *dest, char huge *src, unsigned long size);
void importLib(char *libn);
char *newstr(char *str);
void setLibPath(char *path);
void CheckCode(int uvarsConcerned);
void generateUserVars(void);
void invalidUserVars(void);
void checkUserProc(int varnum, int nargs);
void buildProcErrorMsg(char *d, char *deb, int var);
void tooManyArgsProc(int p);
void notEnoughArgsProc(int p);
void yyparse(void);
void yyerror(char *msg);
void yymessage(char *msg);
void yywarning(char *msg);
int gettoken(char *lltb, int lltbsiz);
void crypt(char *buffer, int len);
int recrypt(char *buffer, char *buffer2, int len);
void cryptXor(char *buffer, unsigned int len);
void setEncoding(char *s);
void honnor(int ver);
void checkStatArg(char *s, char *a1, char *a2, char *a3, char *a4, char *a5, char *a6, char *a7, char *a8, char *a9, char *a10);
int argClass(char *arg);
void checkUserProcArgTypes(char *p, int n);
void updateSym(void);
void emergencyExit(void);
void check_alloc(void *ptr);
void internalFunc(char *f);
void internalProc(char *f);
void checkSymbol(char *s);
void mustHaveUvars(char *n);
FILE *popFile(void);
void pushFile(FILE *file);
void include(char *file, int part);
void *farnormal(void *ptr);
void initLogicalLine(void);
void closeLogicalLine(void);
void setPPOutput(int val);
void pushSource(void);
int identcmp(identListType *p, const char *s2);

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

extern char drive[MAXDRIVE];
extern char dir[MAXDIR];
extern char name[MAXFILE];
extern char ext[MAXEXT];

extern int excludeUserVarsFromCheck;

extern int lineBlocks;
extern int ppoutput;

extern int declaration;
extern int yyStackSize;
extern char forceLet[];
extern int linePart;
extern int rereadLine;
extern int xor17;
extern int cryptppe;
extern int honnorEnc;
extern int maxTokVer;
extern int forceFrt;

extern int onlySyntax;
extern int uvGenerated;

extern FILE *lexin;
extern int errorOccured;
extern int lookupType;
extern int registeringLib;
extern int column;
extern int procfuncdecl;
extern int curProcType;
extern int curArg;
extern FILE *ppe;
extern FILE *sym;
extern FILE *lib;
extern char *libname[];
extern int libnameNum;
extern char far out[];
extern char far symname[];
extern char far strParsed[];
extern char far msg[];
extern char *curProc;
extern int startNVars;
extern int makeSym, makeIntSym, noSymUpdate;
extern long symInc;

extern int makeDebugCod;
extern int makeLib;
extern char far libPath[];

extern int implicitVars;

extern int forceLabel;

extern char yytext[];
extern int ppltoken, ppltype;
extern int lineBlocks;
extern char predefValue[];
extern int nVars;
extern int totalArgs;
extern char userProcArgType[];
extern int totalParam;
extern int statArg;
extern int debug;
extern int line;
extern int localLine;
extern int lexn;
extern int mustBeType;

extern int beginUsed;
extern int userVar;

extern int readProcs;
extern int readGlobal;

extern char nDim;
extern int dim1, dim2, dim3;

extern int identHdr;
extern int procCount;

extern char huge *codeBuffer;
extern long codeBufferSize;
extern signed long codeBufferPos;
extern unsigned long argType;

extern char fakeLabel[7];

extern char **buffers;
extern int buffersSize;
extern int buffersPos;

extern char *buildBuf;
extern int buildSize;
extern int buildPos;
extern int buildAllocated;

extern gotoType **jump;
extern int jumpSize;
extern int jumpPos;

extern identListType **identifier;
extern int identifierSize;
extern int identifierPos;

extern identListType **identList;
extern int identListSize;
extern int identListPos;

extern labelType **labels;
extern int labelSize;
extern int labelPos;

extern signed long nextBufLimit;

extern char **labelStack;
extern int labelStackSize;
extern int labelStackPos;

extern int *loop;
extern int loopSize;
extern int loopPos;

extern char **select;
extern int selectSize;
extern int selectPos;

extern int *paramN;
extern int paramNsize;
extern int paramNpos;

extern symType *symCode;
extern unsigned long symCodePos;
extern unsigned long symCodeSize;
extern unsigned long beginLineOffset;

extern filesType *files;
extern unsigned long filesPos;
extern unsigned long filesSize;

extern char **source;
extern int sourceSize;
extern int sourcePos;
extern int cursource;

extern char loopName[][15];
extern char curFile[];
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± ZERO ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

char *zero(void)
{
char *z = newcode(2);
*z=0;
*(z+1)=0;
return z;
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± ISHEX ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

int isHex(char c)
{
return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'));
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± MKUSERVARIABLE ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

void mkUserVariable(char *name, int type, int ndim1)
{
excludeUserVarsFromCheck=1;
if (ndim1 == 0)
	{
    nDim=0;
    dim1=0;
    }
else
	{
    nDim=1;
    dim1 = ndim1;
    }

dim2=0;
dim3=0;
strcpy(yytext, name);
registerIdent(NULL);
registerIdentList(type);
excludeUserVarsFromCheck=0;
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± TOVAR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

char *toVar(char *sem)
{
char *val;
strcpy(yytext, sem);
val = lookup(SYMBOL);
return val;
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± ANALYZE ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

void analyze(char *s)
{
int a,b;
int p=0;
int n=1;
char pr=32;
int part=0;
int quitit=0;
int cn=1;

for (a=0;a<strlen(s)-1;a++)
	{
    switch (s[a])
    	{
        case '#':
        	if (cn==1)
            	{
                for (b=0;b<strlen(s);b++)
                    {
					if (s[b] == '\"')
			            {
						while (s[b] == '\"' && s[b] != 0)
		    		    	{
							while (s[++b] != '\"' && s[b] != 0);
		    	            b++;
		        	        }
		            	b--;
                        }
					if (s[b] == '\'' || s[b] == ';')
                    	s[b] = 0;
                    }

                while ((&s[a+1])[strlen(&s[a+1])-1] == ' ' ||
				       (&s[a+1])[strlen(&s[a+1])-1] == '\n' ||
					   (&s[a+1])[strlen(&s[a+1])-1] == '\r' ||
					   (&s[a+1])[strlen(&s[a+1])-1] == '\t')
                	(&s[a+1])[strlen(&s[a+1])-1] = 0;

                if (!strncmpi(&s[a+1], "note ", 5))
                	{
                    strcpy(msg, &s[a+6]);
					yymessage(msg);
                    return;
                    }
                if (!strncmpi(&s[a+1], "error ", 6))
                	{
                    strcpy(msg, &s[a+7]);
					yyerror(msg);
                    return;
                    }
                if (!strncmpi(&s[a+1], "warning ", 8))
                	{
                    strcpy(msg, &s[a+9]);
					yywarning(msg);
                    return;
                    }
                if (!strncmpi(&s[a+1], "uses ", 5))
                	{
                    strcpy(msg, &s[a+6]);
                    importLib(msg);
                    return;
                    }
                if (!strncmpi(&s[a+1], "use ", 4))
                	{
                    strcpy(msg, &s[a+5]);
                    importLib(msg);
                    return;
                    }
                if (!strncmpi(&s[a+1], "libpath ", 8))
                	{
                    strcpy(msg, &s[a+9]);
                    setLibPath(msg);
                    return;
                    }
                if (!strncmpi(&s[a+1], "force encoding ", 15))
                	{
                    strcpy(msg, &s[a+16]);
                    setEncoding(msg);
                    return;
                    }
                if (!strncmpi(&s[a+1], "fe ", 3))
                	{
                    strcpy(msg, &s[a+4]);
                    setEncoding(msg);
                    return;
                    }

                // mots seuls
                if (!stricmp(&s[a+1], "uv") ||
                    !stricmp(&s[a+1], "uservar") ||
                    !stricmp(&s[a+1], "user") ||
                    !stricmp(&s[a+1], "u"))
                    {
                    CheckCode(1);
                    userVar = 1;
                    generateUserVars();
                    return;
                    }
                if (!stricmp(&s[a+1], "nuv") ||
                    !stricmp(&s[a+1], "nouservar") ||
                    !stricmp(&s[a+1], "nouser") ||
                    !stricmp(&s[a+1], "nouv") ||
                    !stricmp(&s[a+1], "nu"))
                    {
                    CheckCode(1);
                    userVar = 0;
                    invalidUserVars();
                    return;
                    }
                if (!stricmp(&s[a+1], "debug2") ||
                	!stricmp(&s[a+1], "db2") ||
					!stricmp(&s[a+1], "d2"))
                    {
                    CheckCode(0);
	                makeSym=1;
                    return;
                    }
                if (!stricmp(&s[a+1], "debug") ||
                	!stricmp(&s[a+1], "db") ||
					!stricmp(&s[a+1], "d"))
                    {
                    CheckCode(0);
	                makeIntSym=1;
                    return;
                    }
                if (!stricmp(&s[a+1], "nodebug") ||
					!stricmp(&s[a+1], "nodb") ||
					!stricmp(&s[a+1], "nd"))
	                {
                    CheckCode(0);
	                makeSym=0;
	                makeIntSym=1;
                    return;
                    }
                if (!stricmp(&s[a+1], "syntax"))
                  	{
                    CheckCode(0);
  		           	onlySyntax=1;
                    return;
                    }
                if (!stricmp(&s[a+1], "compile"))
                   	{
                    CheckCode(0);
	               	onlySyntax=0;
                    return;
                    }
                if (!stricmp(&s[a+1], "explicit"))
                	{
	               	implicitVars=0;
                    return;
                    }
                if (!stricmp(&s[a+1], "implicit") ||
                    !stricmp(&s[a+1], "imp"))
                    {
		            implicitVars=1;
                    return;
                    }
                if (!stricmp(&s[a+1], "lib"))
                	{
                    fnsplit(out, drive, dir, name, ext);
                    fnmerge(out, drive, dir, name, ".lib");
                	makeLib=1;
                    return;
                    }
                if (!stricmp(&s[a+1], "ppe"))
                	{
                    fnsplit(out, drive, dir, name, ext);
                    fnmerge(out, drive, dir, name, ".ppe");
                	makeLib=0;
                    return;
                    }
                if (!strcmpi(&s[a+1], "encoding") ||
                    !strcmpi(&s[a+1], "enc"))
                    {
                    honnorEnc=1;
                    return;
                    }
                if (!stricmp(&s[a+1], "flat"))
                	{
                    honnorEnc=0;
                    return;
                    }
                if (!strncmpi(&s[a+1], "include ", 8))
                    {
					include(&s[a+9], part);
                    return;
                    }
                if (!strncmpi(&s[a+1], "pplc_output", 11))
                	{
					setPPOutput(1);
                    return;
                    }
                if (!strncmpi(&s[a+1], "ppc_output", 10))
                	{
					setPPOutput(0);
                    return;
                    }
                yyerror("unknown compiler directive");
                }
            return;
        case '(':
            if (p == 0 && pr == ' ')
				n--;
        	p++;
            break;
        case ')':
        	p--;
            if (p == 0)
            	n++;
            break;
        case '\t':
            s[a]=' ';
        case ' ':
            if (pr != s[a])
				n++;
            break;
        case '=':
            if (p==0 && pr != ' ')
				n++;
        	if (p == 0 && n == 2)
            	forceLet[part]=1;
            if (p==0 && pr != ' ')
				n++;
            break;
        case '\"':
            while (s[a] == '\"' && s[a] != 0)
	        	{
				while (s[++a] != '\"' && s[a] != 0);
                a++;
                }
            a--;
            break;
        case ':':
            if (p == 0)
				{
				n=1;
				pr=32;
                cn=1;
                part++;
                continue;
                }
        	break;
        case ';':
        case '\'':
        	quitit=1;
        case '*':
        	if (cn == 1)
            	{
                checkpplcdirective:
                for (b=0;b<strlen(s);b++)
                    {
					if (s[b] == '\"')
			            {
						while (s[b] == '\"' && s[b] != 0)
		    		    	{
							while (s[++b] != '\"' && s[b] != 0);
		    	            b++;
		        	        }
		            	b--;
                        }
					if ((s[b] == '\'' || s[b] == ';') && b != 0)
                    	s[b] = 0;
                    }

                while ((&s[a+1])[strlen(&s[a+1])-1] == ' ' ||
				       (&s[a+1])[strlen(&s[a+1])-1] == '\n' ||
					   (&s[a+1])[strlen(&s[a+1])-1] == '\r' ||
					   (&s[a+1])[strlen(&s[a+1])-1] == '\t')
                	(&s[a+1])[strlen(&s[a+1])-1] = 0;

                if (!strncmpi(&s[a+1], "$include:", 9))
                    include(&s[a+10], part);
				goto endparse;
				}
            if (quitit)
            	goto endparse;
        	break;
        }
    if (!strncmpi(&s[a], "then ", 5) && pr == 32)
        if (p == 0)
			{
			n=1;
			pr=32;
            part++;
            a+=3;
            cn=1;
            continue;
            }
    if (!strncmpi(&s[a], "else ", 5) && pr == 32)
        if (p == 0)
			{
			n=1;
			pr=32;
            part++;
            a+=3;
            cn=1;
            continue;
            }
    if (!strncmpi(&s[a], "do ", 3) && pr == 32)
        if (p == 0)
			{
			n=1;
			pr=32;
            part++;
            a+=1;
            cn=1;
            continue;
            }
    if (s[a] != ' ' && s[a] != '\t')
    	cn++;
    pr = s[a];
    }

endparse:

if (p > 0)
	yyerror("closing parenthesis not found");
else if (p < 0)
	yyerror("too many closing parenthesis");

}

void checkFunc(int f, int npar)
{
if (func[f].argMini > npar)
	{
    sprintf(msg, "not enough arguments passed to '%s()'", func[f].name);
    yyerror(msg);
    }
else if (func[f].argMini < npar)
	{
    sprintf(msg, "too many arguments passed to '%s()'", func[f].name);
    yyerror(msg);
    }
}

void tooManyArgsProc(int p)
{
sprintf(msg, "too many arguments passed to '%s'", stat[p].name);
yyerror(msg);
}

void notEnoughArgsProc(int p)
{
sprintf(msg, "not enough arguments passed to '%s'", stat[p].name);
yyerror(msg);
}

void pushParamN(int n)
{
while (paramNpos + 1 > paramNsize)
	{
    paramNsize += PARAMNINC;
    paramN = realloc(paramN, paramNsize*sizeof(int));
    check_alloc(paramN);
    }

paramN[paramNpos++] = n;
totalParam=0;
}

int popParamN(void)
{
if (paramNpos == 0)
	yyerror("internal error using parameters stack");
return paramN[--paramNpos];
}

int isInternal(char *name)
{
int a,b;

for (a=0;a<MAXPROCS;a++)
	if (!strcmpi(name, stat[a].name))
    	return 1;

for (a=0;a<MAXFUNCS;a++)
	if (!strcmpi(name, func[a].name))
    	return 1;

for (a=0;a<18;a++)
	if (!strcmpi(name, Type[a]))
    	return 1;

if (!excludeUserVarsFromCheck)
	b = 163;
else
	b = 139;

for (a=0;a<b;a++)
	if (!strcmpi(name, reserved[a]))
    	return 1;

return 0;
}

void registerLibVars(char *name, int libNum)
{
identListType *l;
int a,b,d,e,r, nident;
char f;
int H;
unsigned long blockSize=0;
unsigned long varblocklen;
int prevHdr=0;

if (!openLib(name))
	return;

fread(&blockSize, 4, 1, lib);
fread(&varblocklen, 4, 1, lib);
fread(&nident, 2, 1, lib);
H = identListPos;
for (b=1;b<=nident;b++)
	{
	while (identListPos + 1 > identListSize)
		{
	    identListSize += IDENTIFIERINC;
	    identList = realloc(identList, identListSize*sizeof(identListType *));
        check_alloc(identList);
	    }
    identList[identListPos] = (identListType*) malloc(sizeof(identListType));
    check_alloc(identList[identListPos]);
    l = identList[identListPos];
    l->name=NULL;
    l->data=NULL;
    l->paramTypes=NULL;
    identListPos++;

    fread(&d, 2, 1, lib);
    l->name = malloc(d+1);
    check_alloc(l->name);
    fread(l->name, d, 1, lib); 	// name
    if (*l->name == 1)
    	{
        if (prevHdr != l->name[1])
        	{
			identHdr = ++procCount;
        	prevHdr = l->name[1];
            }
        l->name[1] = identHdr;
        }
    fread(&l->nDim, 1, 1, lib); 	// ndim
    fread(&l->dim1, 2, 1, lib); 	// dim1
    fread(&l->dim2, 2, 1, lib); 	// dim2
    fread(&l->dim3, 2, 1, lib); 	// dim3
    fread(&l->type, 2, 1, lib); 	// vartype
    if (l->type == 7)
    	{
	    fread(&d, 2, 1, lib); 			// len of data
		l->data = malloc(d+1);
        check_alloc(l->data);
	    fread(l->data, d, 1, lib); 		// data
        }
    else
    	{
    	fread(&l->type, 2, 1, lib); 	// vartype
		l->data = malloc(8);
        check_alloc(l->data);
	    fread(l->data, 8, 1, lib); 		// data
        }

    if (l->type == 0xF || l->type == 0x10)
    	{
	    fread(&f, 1, 1, lib);
        l->paramTypes = malloc(f+1);
        check_alloc(l->paramTypes);
        fread(l->paramTypes, f, 1, lib);
        fread(&l->offset, 4, 1, lib);
        }
    else
    	l->paramTypes=NULL;
    l->external=libNum;
    }

for (a=H;a<identListPos;a++)
	{
    if (identList[a]->type == 0x10 || identList[a]->type == 0x0F)
    	{
        e = *((int*)(identList[a]->data)+2);
        e += H;
        *((int*)(identList[a]->data)+2) = e;
        if (identList[a]->type == 0x0F)
        	{
	        r = *((int*)(identList[a]->data)+3);
    	    r += H;
	        *((int*)(identList[a]->data)+3) = r;
            }
        }
	}

fclose(lib);
identHdr=0;
}

int openLib(char *namel)
{

fnsplit(namel,drive,dir,name,ext);
if (*ext == 0)
	strcpy(ext, ".LIB");
fnmerge(msg, drive, dir, name, ext);

if (!(*dir==0 && *drive==0)) // if a path was specified
	{
	if ((lib = fopen(msg, "rb")) == NULL)
		goto failed;
    }
else
	{
	if ((lib = fopen(msg, "rb")) == NULL)
	    {
		fnsplit(libPath, drive, dir, NULL, NULL);
	    fnmerge(msg,drive, dir, name, ext);
		if ((lib = fopen(msg, "rb")) == NULL)
        	goto failed;
        }

	fread(&msg, 25, 1, lib);
	msg[25]=0;
	if (strcmp("Frontier PPL LIB  1.02\r\n\x1A", msg))
		{
		if (!strncmp("Frontier PPL LIB  ", msg, 18) && !strncmp("\r\n\x1A", msg+22, 3))
        	{
			sprintf(msg, "incompatible library version, recompile or get an update (%s%s)\n", name, ext);
		    if (line==0)
            	printf(msg);
	    	else
				yyerror(msg);
            }
        else
        	{
			sprintf(msg, "invalid library (%s%s)\n", name, ext);
	        if (line==0)
			    printf(msg);
	        else
			    yyerror(msg);
            }
	    fclose(lib);
	    return 0;
	    }
	return 1;
    }

failed:
sprintf(msg, "library not found (%s%s)\n", name, ext);
if (line==0)
	printf(msg);
else
	yyerror(msg);
return 0;
}

void insertLibCode(char *name, int libNum)
{
unsigned int offset;
int a;
unsigned long blockSize=0;
unsigned long codesize;
unsigned long varblocklen;
unsigned long i;
unsigned long curp=0;
char *val;
char huge *buffer;
int c;
unsigned int oldline=localLine;
unsigned int oldsource=cursource;
int prevHdr=0;

for (a=0;a<identListPos;a++)
	{
    if (identList[a]->external == libNum && (identList[a]->type == 0x10 || identList[a]->type == 0x0F))
    	{
        identList[a]->offset += codeBufferPos;
        identList[a]->external=0;
        }
	}

if (!openLib(name))
	return;

fread(&blockSize, 4, 1, lib);
fread(&varblocklen, 4, 1, lib);
fseek(lib, varblocklen, SEEK_CUR);
fread(&codesize, 4, 1, lib);

buffer = malloc(codesize);
check_alloc(buffer);

for (curp=0;curp<=codesize;curp+=16384)
	if (codesize - curp >= 16384)
		fread(farnormal(buffer+curp), 1, 16384, lib);
    else
		fread(farnormal(buffer+curp), 1, codesize - curp, lib);

for (i=0;i<codesize;i++)
	{
	if (!strncmp((char *)(buffer+i), "@VAR@", 5))
		{
		c = *(unsigned char *)(buffer+i+8);
        cursource = *(unsigned char *)(buffer+i+5);
		localLine=*(unsigned int*)(buffer+i+6);
		strncpy(msg, (char *)(buffer+i+9), c);
		msg[c]=0;
		if (*msg == 1)
			{
			if (prevHdr != msg[1])
				{
				identHdr = ++procCount;
				prevHdr = msg[1];
				}
			msg[1] = identHdr;
			}
		registeringLib=1;
		strcpy(yytext, msg);
		val = lookup(SYMBOL);
		registeringLib=0;
		if (val == NULL)
			{
			yyerror("internal error: unresolved external variable");
			free(buffer);
			return;
			}
		i -= 2;
		*(int *)(buffer+i) = *(int *)(val+2);
		i += 2;
		continue;
		}
	if (!strncmp((char *)(buffer+i), "@LBL@", 5))
		{
		c = *(unsigned char*)(buffer+i+8);
        cursource = *(unsigned char*)(buffer+i+5);
		localLine=*(unsigned int*)(buffer+i+6);
		if (*(char *)(buffer+i+9) == 1)
			*(char *)(buffer+i+11) = libNum+2;
		else
			*(char *)(buffer+i+9) = libNum+2;
		}
	if (!strncmp((char *)(buffer+i), "@JMP@", 5))
		{
		c = *(unsigned char*)(buffer+i+8);
        cursource = *(unsigned char*)(buffer+i+5);
		localLine=*(unsigned int*)(buffer+i+6);
		if (*(char *)(buffer+i+9) == 1)
			*(char *)(buffer+i+11) = libNum+2;
		else
			*(char *)(buffer+i+9) = libNum+2;
		}
	}

localLine=oldline;
cursource=oldsource;

while (codeBufferPos + codesize > codeBufferSize)
	{
	codeBufferSize += CODEBUFFERINC;
	codeBuffer = farrealloc(codeBuffer, codeBufferSize);
	check_alloc(codeBuffer);
	}
mymemcpy(codeBuffer+codeBufferPos, buffer, codesize);
codeBufferPos += codesize;
free(buffer);
}

void writecode(char *file)
{
unsigned long curp;
ppe = fopen(file, "wb");
for (curp=0;curp<=codeBufferPos;curp+=16384)
	if (codeBufferPos - curp >= 16384)
		fwrite(farnormal(codeBuffer+curp), 1, 16384, ppe);
	else
		fwrite(farnormal(codeBuffer+curp), 1, codeBufferPos - curp, ppe);
fclose(ppe);
}

void mymemcpy(char huge *dest, char huge *src, unsigned long size)
{
unsigned long curp;

if (size < 32767)
    {
	memcpy(dest, src, size);
    return;
    }

for (curp=0;curp<=size;curp+=16384)
	if (size - curp >= 16384)
		memcpy(farnormal(dest+curp), farnormal(src+curp), 16384);
    else
		memcpy(farnormal(dest+curp), farnormal(src+curp), size-curp);

}

void importLib(char *libn)
{
if (makeLib != 0)
	yyerror("cannot generate a library if using library");

while(*libn==' ' && *libn!=0)
   	strcpy(libn,libn+1);

CheckCode(0);

if (libnameNum==252)
	{
    yyerror("maximum number of libraries reached");
    return;
    }
libname[libnameNum++] = newstr(libn);
registerLibVars(libname[libnameNum-1], libnameNum);
}

char *newstr(char *str)
{
char *p;

while(*str==' ' && *str!=0)
   	strcpy(str,str+1);

if (str[strlen(str)-1] == '\n')
	str[strlen(str)-1] = 0;

p = malloc(strlen(str)+1);
check_alloc(p);
strcpy(p, str);
return p;
}

void setLibPath(char *path)
{

CheckCode(0);

while(*path==' ' && *path!=0)
   	strcpy(path,path+1);

if (path[strlen(path)-1] == '\n')
	path[strlen(path)-1] = 0;

strcpy(libPath, path);
if (libPath[strlen(libPath)-1] != '\\')
	strcat(libPath, "\\");
}

void CheckCode(int uvarsConcerned)
{
if (codeBufferPos > 0)
	{
	yyerror("global compiler directives must declared before any code");
	return;
    }

if (uvarsConcerned && ((identListPos > 0 && !uvGenerated) || (uvGenerated && identListPos > 24)))
	{
	yyerror("user variable generation compiler directives must declared before any code/lib");
	return;
    }
}

void generateUserVars(void)
{
if (userVar && !uvGenerated)
	{
    mkUserVariable("U_Expert", 0, 0);
    mkUserVariable("U_FSE", 0, 0);
    mkUserVariable("U_FSEP", 0, 0);
    mkUserVariable("U_Cls", 0, 0);
    mkUserVariable("U_ExpDate", 2, 0);
    mkUserVariable("U_Sec", 4, 0);
    mkUserVariable("U_PageLen", 4, 0);
    mkUserVariable("U_ExpSec", 4, 0);
    mkUserVariable("U_City", 7, 0);
    mkUserVariable("U_BDPhone", 7, 0);
    mkUserVariable("U_HVPhone", 7, 0);
    mkUserVariable("U_Trans", 7, 0);
    mkUserVariable("U_Cmnt1", 7, 0);
    mkUserVariable("U_Cmnt2", 7, 0);
    mkUserVariable("U_Pwd", 7, 0);
    mkUserVariable("U_Scroll", 0, 0);
    mkUserVariable("U_LongHDR", 0, 0);
    mkUserVariable("U_Def79", 0, 0);
    mkUserVariable("U_Alias", 7, 0);
    mkUserVariable("U_Ver", 7, 0);
    mkUserVariable("U_Addr", 7, 5);
    mkUserVariable("U_Notes", 7, 4);
    mkUserVariable("U_PwdExp", 2, 0);
    mkUserVariable("U_Account", 4, 0);
    uvGenerated=1;
	}
}

void invalidUserVars(void)
{
int a,b;
if (!uvGenerated)
	return; //yyerror("internal error: cannot invalid user vars, user vars not generated");

for (a=0;a<24;a++)
    {
	free(identList[0]->name);
	free(identList[0]->data);
    if (identList[0]->paramTypes != NULL)
		free(identList[0]->paramTypes);
    free(identList[0]);
    for (b=0;b<identListPos-1;b++)
        identList[b] = identList[b+1];
    identListPos--;
    }
uvGenerated=0;
}

void checkUserProc(int varnum, int nargs)
{
int n;
varnum--;

if (identList[varnum]->type != 0x0F && identList[varnum]->type != 0x10)
	yyerror("internal error verifying proc/func argument numbers");

n = *(char*)identList[varnum]->data;

if (nargs > n)
	{
    buildProcErrorMsg(msg, "too many arguments passed to ", varnum);
    yyerror(msg);
    }

if (nargs < n)
	{
    buildProcErrorMsg(msg, "not enough arguments passed to ", varnum);
    yyerror(msg);
    }
}

void buildProcErrorMsg(char *d, char *deb, int var)
{
int f,a,e;
char *pt;
int bm;

if (identList[var]->type != 0x10 && identList[var]->type != 0x0F)
	yyerror("internal error building proc/func params");

strcpy(d, deb);
strcat(d, identList[var]->type == 0x10 ? "procedure " : "function ");
strcat(d, identList[var]->name);
strcat(d, "(");

f = *(char*)identList[var]->data;
e = *((int*)(identList[var]->data)+2);
bm = *((int*)(identList[var]->data)+3);
pt = identList[var]->paramTypes;

for (a=0;a<f;a++)
	{
    if (a>0)
    	strcat(d, ", ");
    if (identList[var]->type == 0x10 && (bm & (1 << a)))
    	strcat(d, "Var ");
    strcat(d, Type[pt[a]]);
    strcat(d, " ");
    strcat(d, (char *)(identList[e]->name)+2);
    e++;
    }

strcat(d, ")");
if (identList[var]->type == 0x0F)
	{
	strcat(d, " ");
    f = *((int*)identList[var]->data+3);
	strcat(d, Type[identList[f]->type]);
    }
}

void setEncoding(char *s)
{
if (strlen(s) > 1)
	{
    unk:
    strcpy(msg, "unknown encoding method");
    if (line>0)
    	yyerror(msg);
    else
    	printf("%s\n", msg);
    return;
    }
switch (*s)
	{
    case '0':
        honnorEnc=0;
    	cryptppe=0;
        xor17=0;
        break;
    case '1':
        honnorEnc=0;
        cryptppe=1;
        xor17=0;
        break;
    case '2':
        honnorEnc=0;
    	cryptppe=1;
        xor17=1;
        break;
    case '3':
        honnorEnc=0;
    	cryptppe=0;
        xor17=0;
        forceFrt=1;
        break;
    default:
    	goto unk;
    }
}

void honnor(int ver)
{
if (!honnorEnc)
	return;

if (ver > maxTokVer)
	maxTokVer = ver;
}

void checkStatArg(char *s, char *a1, char *a2, char *a3, char *a4, char *a5, char *a6, char *a7, char *a8, char *a9, char *a10)
{
int st = *(s+2);
char at[10]; // argtype used in source
char mt[10]; // mandatory type
int a;

at[0] = argClass(a1);
at[1] = argClass(a2);
at[2] = argClass(a3);
at[3] = argClass(a4);
at[4] = argClass(a5);
at[5] = argClass(a6);
at[6] = argClass(a7);
at[7] = argClass(a8);
at[8] = argClass(a9);
at[9] = argClass(a10);

for (a=0;a<10;a++)
	mt[a]=0;

switch (stat[st].argType)
    {
	case 0x075F:
    case 0x08B7:
		mt[0] = 1;
		break;

	case 0x075B:
		mt[0] = 1;
		mt[1] = 1;
		break;

	case 0x07B5:
		mt[1] = 1;
		break;

	case 0x07E5:
		mt[2] = 1;
		break;

	case 0x078C:
		mt[0] = 1;
		mt[1] = 1;
		break;

	case 0x0836:
		mt[0] = 2;
		break;

	case 0x088C:
		mt[0] = 2;
		mt[1] = 2;
		break;

	case 0x2585:
		mt[3] = 2;
		break;

    case 0x756:
    	mt[0] = 1;
    	mt[1] = 1;
    	mt[2] = 1;
        break;

	default:
		break;
    }

for (a=0;a<10;a++)
	{
    switch (mt[a])
    	{
        case 1:
        	if (at[a] != ARGVAR && at[a] != ARGARR)
            	{
				sprintf(msg, "argument %d of '%s' must be a variable", a, stat[st].name);
                yyerror(msg);
                }
        	break;
        case 2:
        	if (at[a] != ARGARR)
            	{
				sprintf(msg, "argument %d of '%s' must be an array", a, stat[st].name);
                yyerror(msg);
                }
            break;
        }
	}


}

int argClass(char *arg)
{
char *p;
int n;
unsigned char c;

if (arg == NULL)
	return ARGNONE;

p=arg+2;
n = (*(int*)p)-1;

if (strncmp(p+2, "@VAR@", 5))
	return ARGEXP;

c = *(unsigned char *)(p+10);
strncpy(msg, (char *)(p+11), c);
msg[c]=0;

p = (char *)&msg;
if (*p == 1)
	p+=2;

if ((*p >= '0' && *p <= '9') || *p == '\"')
	return ARGIMM;

if (identList[n]->nDim != 0)
	return ARGARR;

return ARGVAR;
}

void checkUserProcArgTypes(char *p, int n)
{
int pn = (*(int*)(p+2))-1;
char bm = *(((int *)(identList[pn]->data))+3);
int a;

for (a=0;a<n && a < 16;a++)
	{
    if (bm & (1 << a) && (userProcArgType[a] != ARGVAR && userProcArgType[a] != ARGARR))
    	{
        sprintf(msg, "argument %d of %s() must be a variable", a+1, identList[pn]->name);
    	yyerror(msg);
        }
    }
}

void updateSym(void)
{
if ((makeSym || makeIntSym) && !noSymUpdate)
	{
    while (symCodePos + 1 > symCodeSize)
	    {
        symCodeSize += SYMCODEINC;
        symCode = realloc(symCode, symCodeSize*sizeof(symType));
        check_alloc(symCode);
        }
    symCode[symCodePos].codeOffset = codeBufferPos;
    symCode[symCodePos].sourceOffset = beginLineOffset+symInc;
    symCode[symCodePos].line = localLine;
    symCodePos++;
    }
}

void emergencyExit(void)
{
unallocMem();
freeBuffers();
}

void check_alloc(void *ptr)
{
if (ptr == NULL)
	{
	yyerror("not enough memory");
	emergencyExit();
	exit(-1);
    }
}

void internalFunc(char *f)
{
sprintf(msg, "cannot use '%s' (internal) as an identifier name", func[*(int*)(f+2)]);
yyerror(msg);
}

void internalProc(char *f)
{
sprintf(msg, "cannot use '%s' (internal) as an identifier name", stat[*(int*)(f+2)]);
yyerror(msg);
}

void checkSymbol(char *s)
{
char tmp[256];

strncpy(tmp, yytext, 255);
strncpy(yytext, s, 255);

if (lookup(SYMBOL) != 0)
	{
	if ((*yytext >= '0' && *yytext <= '9') || *yytext == '\"')
		sprintf(msg, "symbol '%s' is a constant", yytext);
    else
		sprintf(msg, "symbol '%s' already defined", yytext);
	yyerror(msg);
    strncpy(yytext, tmp, 255);
	return;
	}
strncpy(yytext, tmp, 255);
}

void mustHaveUvars(char *n)
{
if (!userVar)
	{
	sprintf(msg, "'%s' needs user variable generation", n);
    yyerror(msg);
    }
}

void pushFile(FILE *file)
{
while (filesPos + 1 > filesSize)
	{
    filesSize += FILESINC;
    files = realloc(files, filesSize*sizeof(filesType));
    check_alloc(files);
    }

files[filesPos].stream = file;
files[filesPos].line = localLine;
files[filesPos].cursource = cursource;
filesPos++;
localLine=0;
}

FILE *popFile(void)
{
if (filesPos == 0)
	{
	yyerror("internal error returning from included file");
    return NULL;
    }
filesPos--;
localLine = files[filesPos].line;
return files[filesPos].stream;
}

void include(char *file, int part)
{
FILE *tmp;
if (part > 0)
    yyerror("include directive must be on a simple line");
strcpy(msg, file);
while(*msg==' ' && *msg!=0)
	strcpy(msg,msg+1);
if ((tmp = fopen(msg, "rt")) == NULL)
    {
    strcpy(name, msg);
    sprintf(msg, "cannot open included file (%s)", name);
    yyerror(msg);
    }
else
    {

	fnsplit(file, NULL, NULL, name, ext);
	fnmerge(curFile, NULL, NULL, name, ext);

    if (sourcePos == 255)
    	yyerror("can only include up to 255 files");

	pushFile(lexin);
    pushSource();
    cursource = sourcePos-1;

    lexin = tmp;
    rereadLine=1;
    }
}

void *farnormal(void *ptr)
{
      size_t seg, ofs;

      seg = FP_SEG(ptr);
      ofs = FP_OFF(ptr);
      return MK_FP(seg + (ofs >> 4), ofs & 0xf);
}

void initLogicalLine(void)
{
    forceLabel=0;
    declaration=0;
    mustBeType=0;
	procfuncdecl=0;
    curArg=0;
    statArg=0;
    totalArgs=0;
    totalParam=0;
    lexn=0;
    allocBuffers();
}

void closeLogicalLine(void)
{
char *t;
if (*fakeLabel != 0)
   	{
    strcpy(yytext, fakeLabel);
    t = mkStat(65534);
    sendToBuffer(t+2, *(int *)t);
    *fakeLabel = 0;
    }
freeBuffers();
}

void setPPOutput(int val)
{
ppoutput = val;
if (ppoutput)
	lineBlocks = 1;
else
	lineBlocks = 2048;
}

void pushSource(void)
{
	while (sourcePos + 1 > sourceSize)
		{
	    sourceSize += SOURCEINC;
	    source = realloc(source, sourceSize*sizeof(char *));
	    check_alloc(source);
	    }

	source[sourcePos] = calloc(strlen(curFile)+1, 1);
    strcpy(source[sourcePos++], curFile);
}
