/*

  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

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

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 {
    char *name;
	int minArg;
    int maxArg;
    int argType;
    int reserved;
	}statement;

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

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

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 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(int loopType);
void checkLoop(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, int a);
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 libSize(int line, long size);
void linking(int line);
void codeSize(int line, long size);
void importLib(char *libn);
char *newstr(char *str);
void setLibPath(char *path);
void setEncoding(char *s);
void readIniFile(char *path);
void setPPOutput(int val);

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

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

int rotCharPos = 0;
char rotChar[5] = "|/-\\";
int warning=0;

extern char curFile[];
extern int lineBlocks;
extern int ppoutput;

extern int declaration;
extern int yyStackSize;
extern int forceLet;
extern int cryptppe;
extern int xor17;
extern int honnorEnc;
extern int forceFrt;

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

extern int implicitVars;
extern int implicitType;

extern char yytext[256];
extern int ppltoken, ppltype;
extern char predefValue[12];
extern int nVars;
extern int totalArgs;
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 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 char loopName[5][15];

extern statement far stat[];
extern function far func[];

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

extern int onlySyntax;

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± MAIN ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

int main(int argc, char **argv)
{
char file[256]="";
int a;
FILE *res = NULL;
char par[256];

#pragma warn -eff
Fortify_EnterScope();
#pragma warn .eff
#if defined( __DPMI16__)
    printf("PowerPPL Compiler v1.00 Public Beta 3 àlpha version A.11 - DPMI Version\n(c) 1996,97 The Aegis Corporation\n\n");
#else
    printf("PowerPPL Compiler v1.00 Public Beta 3 àlpha version A.11\n(c) 1996,97 The Aegis Corporation\n\n");
#endif

if (argc < 2)
	{
    printf("Usage: ppc [{+-}switch] [-option] filename[.pps] [filename[.lib] ...]\n"
           "\n"
           "  +switch : turn on option         -switch : turn off option\n"
           "\n"
           "  switch  action when turned on\n"
           "  d       make debug code (powerppl debugger integrated format)\n"
           "  d2      make debug code (ppldebug .SYM format)\n"
           "  dc      write debug.cod file (for internal debug purpose)\n"
           "  f       force flat PPE 2.00, do not honnor pcb encoding convention\n"
           "  h       force honnor pcb encoding convention (autodetect crypting version)\n"
           "  imp     set implicit variable declaration on (autodeclare option)\n"
           "  l       list source while compiling\n"
           "  lib     compile to .LIB library rather than .PPE\n"
           "  o       use alternate output style (PPLC-like)\n"
           "  s       only check syntax (don't create .PPE)\n"
           "  u       generates user variables\n"
           "\n"
           "Options:\n"
           "  -feN    force pcb encoding type. N=coding method\n"
           "  -lpXXXX specify library path. ie: lpC:\\PP\\LIB\n");
    exit(-1);
    }

readIniFile(argv[0]);

a = 0;
for (;;)
	{
    a++;
    if (a>=argc && res == NULL)
    	break;

    if (res != NULL)
    	{
        a--;
        fgets(par, 255, res);
        if (par[strlen(par)-1] == '\n')
			par[strlen(par)-1] = 0;
        if (feof(res))
        	{
            fclose(res);
            res= NULL;
            continue;
            }
        }
    else
    	strncpy(par, argv[a], 255);

    switch ( *par )
    	{
        case '@':
        	if ((res = fopen(&argv[a][1], "rt")) == NULL)
            	{
                printf("cannot open @response file\n");
                exit(-1);
                }
            break;
		case '-':
        	treatOption(&par[1],0);
            break;
		case '+':
        	treatOption(&par[1],1);
            break;
        default :
			fnsplit(par,drive,dir,name,ext);
            if (!stricmp(ext, ".lib") || *file != 0)
            	{
                if (libnameNum==254)
                	{
                    printf("too many libraries specified\n");
                    exit(-1);
                    }
                libname[libnameNum++] = newstr(par);
                }
            else
            	{
				if (*ext == 0)
					strcpy(ext, ".pps");
				fnmerge(file,drive,dir,name,ext);
    	        break;
            	}
        }
    }

if (*file==0)
	{
	printf("no source specified\n");
    exit(-1);
    }

if (access(file, 0) != 0)
	{
	printf("file not found (%s)\n", file);
    exit(-1);
    }
if (makeLib)
	fnmerge(out,drive,dir,name,".lib");
else
	fnmerge(out,drive,dir,name,".ppe");
fnmerge(symname,drive,dir,name,".sym");

allocMem();

compile(file);

unallocMem();

#pragma warn -eff
Fortify_LeaveScope();
#pragma warn .eff
if (errorOccured)
	return 4;
if (warning)
	return 1;
return 0;
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± TREATOPTION ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

void treatOption(char *o, int a)
{
if (!strcmpi(o, "u"))  		{ userVar = a; return; }
if (!strcmpi(o, "uv"))  	{ userVar = a; return; }
if (!strcmpi(o, "l"))   	{ debug = a; return; }
if (!strcmpi(o, "d"))   	{ makeIntSym = a; return; }
if (!strcmpi(o, "d2"))   	{ makeSym = a; return; }
if (!strcmpi(o, "dc"))  	{ makeDebugCod = a; return; }
if (!strcmpi(o, "f"))  	    { honnorEnc = !a; cryptppe=0; xor17=0; return; }
if (!strcmpi(o, "h"))  		{ honnorEnc = a; return; }
if (!strcmpi(o, "imp")) 	{ implicitVars=a; return; }
if (!strncmpi(o, "fe", 2))  { setEncoding(o+2); return; }
if (!strncmpi(o, "lp", 2)) 	{ setLibPath(o+2); return; }
if (!strcmpi(o, "s"))   	{ onlySyntax = a; return; }
if (!strcmpi(o, "lib"))   	{ makeLib = a; return; }
if (!strcmpi(o, "fr"))      { forceFrt = a; return; }
if (!strcmpi(o, "o"))       { setPPOutput(a); return; }
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± YYERROR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

void yyerror(char *s)
{
    while(*s==' ' && *s!=0)
    	strcpy(s,s+1);
	fflush(stdout);

    if (!debug && !errorOccured)
    	{
        if (!ppoutput)
        	{
	        printf("\r                               \rerror file %s line %d:\n", source[cursource], localLine);
			printf(strParsed);
        	if (strParsed[strlen(strParsed)-1] != '\n')
	        	printf("\n");
    	    }
        else
        	printf("\n\nError in file %s, line %d\n", source[cursource], localLine);
        }
    if (!strcmpi(s, "syntax error"))
    	{
        if (declaration)
			{
			if (!errorOccured)
				{
                if (!ppoutput)
					printf("%*s\n%*s\n", column, "^", column, "declaration syntax error");
                else
                	printf("%s\n\n", "declaration syntax error");
				}
			}
        else
			{
			if (!errorOccured)
				{
                if (!ppoutput)
					printf("%*s\n%*s\n", column, "^", column, "expression syntax error");
                else
                	printf("%s\n\n", "expression syntax error");
				}
			}
        }
    else
    	{
		if (!errorOccured)
			{
            if (!ppoutput)
				printf("%*s\n%*s\n", column, "^", column, s);
            else
               	printf("%s\n\n", s);
			}
		}

    if (ppoutput && !errorOccured)
	    printf("Error(s) encountered, compile aborted...\n");

    errorOccured=1;
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± YYWARNING ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

void yywarning(char *s)
{
    while(*s==' ' && *s!=0)
    	strcpy(s,s+1);
	fflush(stdout);
    warning=1;
    if (!debug)
    	{
        if (!ppoutput)
        	{
	        printf("\r                               \rwarning file %s line %d:\n", source[cursource],localLine);
			printf(strParsed);
        	if (strParsed[strlen(strParsed)-1] != '\n')
        		printf("\n");
    	    }
        else
        	printf("\n\nWarning in file %s, line %d\n", source[cursource], localLine);
        }
    if (!ppoutput)
		printf("%*s\n%*s\n", column, "^", column, s);
    else
   		printf("%s\n\n", s);
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± YYMESSAGE ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

void yymessage(char *s)
{
    while(*s==' ' && *s!=0)
    	strcpy(s,s+1);
	fflush(stdout);
    if (!debug)
    	{
        if (!ppoutput)
        	{
	        printf("\r                               \rmessage file %s line %d:\n", source[cursource],localLine);
			printf(strParsed);
        	if (strParsed[strlen(strParsed)-1] != '\n')
        		printf("\n");
    	    }
        else
        	printf("\n\nMessage in file %s, line %d\n", source[cursource], localLine);
        }
    if (!ppoutput)
		printf("%*s\n%*s\n", column, "^", column, s);
    else
   		printf("%s\n\n", s);
}

// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
// ±±±± WRITELINES ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
// ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

void writeLines(int line)
{
static int first=1;

if (!errorOccured)
	{
    if (!ppoutput)
		printf("\r%d line%s compiled", line, line>0 ? "s" : "");
    else
    	{
        if (first)
        	{
            printf("Pass 1 ... ");
            first=0;
            rotCharPos=0;
            }
        printf("%c\b",rotChar[rotCharPos++]);
        rotCharPos %= 4;
        }
    }
}

void libSize(int line, long size)
{
if (!errorOccured)
	{
    if (!ppoutput)
		printf("\r%d lines compiled. Library code size: %ld bytes\n", line, size);
    else
    	printf("\rSource compilation complete...\n");
    }
}

void linking(int line)
{
static int first=1;

if (!errorOccured)
	{
    if (!ppoutput)
		printf("\r%d line%s compiled. Linking...", line, line>0 ? "s" : "");
    else
    	{
        if (first)
        	{
            printf(" \n\nPass 2 ... ");
            first=0;
            rotCharPos=0;
            }
        printf("%c\b",rotChar[rotCharPos++]);
        rotCharPos %= 4;
        }
    }
}

void codeSize(int line, long size)
{
if (!errorOccured)
	{
    if (!ppoutput)
		printf("\r%d lines compiled. Code size: %ld bytes\n", line, size);
    else
    	printf(" \n\nSource compilation complete...\n");
    }
}

void readIniFile(char *path)
{
char filename[256];
const char far *pathSection = "Paths";
const char far *compileSection = "Compilation";
const char far *encodingSection = "Encoding";
const char far *intDbSection = "Internal_Debugging";
const char far *miscSection = "Misc";
int a;

fnsplit(path, drive, dir, NULL, NULL);
fnmerge(filename, drive, dir, "PPC", ".INI");

*msg=0;
getProfileString( pathSection, "LibPath", "", msg, 255, filename);
if (*msg != 0)
	setLibPath(msg);

userVar = getProfileInt( compileSection, "UserVars", 1, filename );
makeIntSym = getProfileInt( compileSection, "DebugSymbols", 0, filename );
makeSym = getProfileInt( compileSection, "DebugSymbols2", 0, filename );
implicitVars = getProfileInt( compileSection, "ImplicitVars", 0, filename );
makeLib = getProfileInt( compileSection, "MakeLib", 0, filename );
onlySyntax = getProfileInt( compileSection, "CheckSyntaxOnly", 0, filename );
if (getProfileInt( encodingSection, "ForceEncoding", 0, filename ))
	{
    getProfileString( encodingSection, "ForceEncodingType", "0", msg, 255, filename );
	setEncoding(msg);
    }
makeDebugCod = getProfileInt( intDbSection, "GenDebugFile", 0, filename );
debug = getProfileInt( intDbSection, "Listing", 0, filename );
a = getProfileInt( miscSection, "PPLClikeOutput", 0, filename );
setPPOutput(a);
}
