/********************************************************************** * pas.c * Main process * * Copyright (C) 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * **********************************************************************/ /********************************************************************** * Included Files **********************************************************************/ #define _GNU_SOURCE #include #include #include #include #include #include #include "config.h" #include "keywords.h" #include "pdefs.h" #include "ptdefs.h" #include "podefs.h" #include "pedefs.h" #include "pas.h" #include "paslib.h" /* For extension */ #include "pproc.h" /* For primeBuiltInProcedures */ #include "pfunc.h" /* For primeBuiltInFunctions */ #include "ptkn.h" /* For primeTokenizer */ #include "ptbl.h" /* For primeSymbolTable */ #include "pofflib.h" /* For poffInitializeForOutput() */ #include "poff.h" /* For POFF definitions */ #include "pprgm.h" /* for program() */ #include "punit.h" /* for unit() */ #include "perr.h" /* for error() */ /********************************************************************** * Definitions **********************************************************************/ /********************************************************************** * Global Variables **********************************************************************/ /* Unitialized Global Data */ uint16 token; /* Current token */ uint16 tknSubType; /* Extended token type */ sint32 tknInt; /* Integer token value */ float64 tknReal; /* Real token value */ STYPE *tknPtr; /* Pointer to symbol token*/ WTYPE withRecord; /* RECORD used with WITH statement */ FTYPE files[MAX_FILES+1]; /* File Table */ fileState_t fileState[MAX_INCL]; /* State of all open files */ /* sourceFileName : Program name from command line * includePath[] : Pathes to search when including file */ char *sourceFileName; char *includePath[MAX_INCPATHES]; poffHandle_t poffHandle; /* Handle for POFF object */ FILE *poffFile; /* Pass1 POFF output file */ FILE *lstFile; /* List File pointer */ FILE *errFile; /* Error file pointer */ /* Initialized Global Data */ sint16 level = 0; /* Static nesting level */ sint16 includeIndex = 0; /* Include file index */ sint16 nIncPathes = 0; /* Number pathes in includePath[] */ uint16 label = 0; /* Last label number */ sint16 nsym = 0; /* Number symbol table entries */ sint16 nconst = 0; /* Number constant table entries */ sint16 sym_strt = 0; /* Symbol search start index */ sint16 const_strt = 0; /* Constant search start index */ sint16 err_count = 0; /* Error counter */ sint16 nfiles = 0; /* Program file counter */ sint32 warn_count = 0; /* Warning counter */ sint32 dstack = 0; /* data stack size */ /********************************************************************** * Private Type Definitions **********************************************************************/ struct outFileDesc_s { const char *extension; const char *flags; FILE **stream; }; typedef struct outFileDesc_s outFileDesc_t; /********************************************************************** * Private Variables **********************************************************************/ static const outFileDesc_t outFiles[] = { { "o1", "wb", &poffFile }, /* Pass 1 POFF object file */ #if LSTTOFILE { "lst", "w", &lstFile }, /* List file */ #endif { "err", "w", &errFile }, /* Error file */ { NULL, NULL } /* (terminates list */ }; static const char *programName; /*********************************************************************** * Private Function Prototypes ***********************************************************************/ static void closeFiles(void); static void openOutputFiles(void); static void showUsage(void); static void parseArguments(int argc, char **argv); /*********************************************************************** * Private Functions ***********************************************************************/ static void closeFiles(void) { const outFileDesc_t *outFile; /* Close input source files */ for(; includeIndex >= 0; includeIndex--) { if (FP->stream) { (void)fclose(FP->stream); FP->stream = NULL; } } /* Close output files */ for (outFile = outFiles; outFile->extension; outFile++) { if (*outFile->stream) { (void)fclose(*outFile->stream); *outFile->stream = NULL; } } } /***********************************************************************/ static void openOutputFiles(void) { const outFileDesc_t *outFile; char tmpname[FNAME_SIZE+1]; /* Open output files */ for (outFile = outFiles; outFile->extension; outFile++) { /* Generate an output file name from the source file * name and an extension associated with the output file. */ (void)extension(sourceFileName, outFile->extension, tmpname, 1); *outFile->stream = fopen(tmpname, outFile->flags); if (*outFile->stream == NULL) { fprintf(stderr, "Could not open output file '%s': %s\n", tmpname, strerror(errno)); showUsage(); } } } /***********************************************************************/ static void signalHandler(int signo) { #ifdef _GNU_SOURCE fprintf(errFile, "Received signal: %s\n", strsignal(signo)); fprintf(lstFile, "Received signal: %s\n", strsignal(signo)); #else fprintf(errFile, "Received signal %d\n", signo); fprintf(lstFile, "Received signal %d\n", signo); #endif closeFiles(); error(eRCVDSIGNAL); exit(1); } /***********************************************************************/ static void primeSignalHandlers(void) { (void)signal(SIGHUP, signalHandler); (void)signal(SIGINT, signalHandler); (void)signal(SIGQUIT, signalHandler); (void)signal(SIGILL, signalHandler); (void)signal(SIGABRT, signalHandler); (void)signal(SIGSEGV, signalHandler); (void)signal(SIGTERM, signalHandler); } /***********************************************************************/ static void showUsage(void) { fprintf(stderr, "USAGE:\n"); fprintf(stderr, " %s [options] \n", programName); fprintf(stderr, "[options]\n"); fprintf(stderr, " -I\n"); fprintf(stderr, " Search in for additional file\n"); fprintf(stderr, " A maximum of %d pathes may be specified\n", MAX_INCPATHES); fprintf(stderr, " (default is current directory)\n"); closeFiles(); exit(1); } /* end showUsage */ /***********************************************************************/ static void parseArguments(int argc, char **argv) { int i; programName = argv[0]; /* Check for existence of at least the filename argument */ if (argc < 2) { fprintf(stderr, "Invalid number of arguments\n"); showUsage(); } /* Parse any optional command line arguments */ for (i = 1; i < argc-1; i++) { char *ptr = argv[i]; if (ptr[0] == '-') { switch (ptr[1]) { case 'I' : if (nIncPathes >= MAX_INCPATHES) { fprintf(stderr, "Unrecognized [option]\n"); showUsage(); } else { includePath[nIncPathes] = &ptr[2]; nIncPathes++; } break; default: fprintf(stderr, "Unrecognized [option]\n"); showUsage(); } } else { fprintf(stderr, "Unrecognized [option]\n"); showUsage(); } } /* Extract the Pascal program name from the command line */ sourceFileName = argv[argc-1]; } /*********************************************************************** * Public Functions ***********************************************************************/ int main(int argc, char *argv[]) { char filename [FNAME_SIZE+1]; /* Parse command line arguments */ parseArguments(argc, argv); /* Open all output files */ openOutputFiles(); #if !LSTTOFILE lstFile = stdout; #endif /* Open source file -- Use .PAS or command line extension, if supplied */ (void)extension(sourceFileName, "PAS", filename, 0); fprintf(errFile, "%01x=%s\n", FP->include, filename); memset(FP, 0, sizeof(fileState_t)); FP->stream = fopen(filename, "r"); if (!FP->stream) { errmsg("Could not open source file '%s': %s\n", filename, strerror(errno)); showUsage(); } /* Initialization */ primeSignalHandlers(); primeSymbolTable(MAX_SYM); primeBuiltInProcedures(); primeBuiltInFunctions(); primeTokenizer(MAX_STRINGS); /* Initialize the POFF object */ poffHandle = poffCreateHandle(); if (poffHandle == NULL) fatal(eNOMEMORY); /* Save the soure file name in the POFF output file */ FP->include = poffAddFileName(poffHandle, filename); /* Define standard input/output file characteristics */ files[0].defined = -1; files[0].flevel = level; files[0].ftype = sCHAR; files[0].faddr = dstack; files[0].fsize = sCHAR_SIZE; dstack += sCHAR_SIZE; /* We need the following in order to calculate relative stack positions. */ FP->dstack = dstack; /* Indicate that no WITH statement has been processed */ memset(&withRecord, 0, sizeof(WTYPE)); /* Process the pascal program * * FORM: pascal = program | unit * FORM: program = program-heading ';' [uses-section ] block '.' * FORM: program-heading = 'program' identifier [ '(' identifier-list ')' ] * FORM: unit = unit-heading ';' interface-section implementation-section init-section * FORM: unit-heading = 'unit' identifer */ getToken(); if (token == tPROGRAM) { /* Compile a pascal program */ FP->kind = eIsProgram; FP->section = eIsProgramSection; getToken(); program(); } else if (token == tUNIT) { /* Compile a pascal unit */ FP->kind = eIsUnit; FP->section = eIsOtherSection; getToken(); unitImplementation(); } else { /* Expected 'program' or 'unit' */ error(ePROGRAM); } /* Dump the symbol table content (debug only) */ #if CONFIG_DEBUG dumpTables(); #endif /* Write the POFF output file */ poffWriteFile(poffHandle, poffFile); poffDestroyHandle(poffHandle); /* Close all output files */ closeFiles(); /* Write Closing Message */ if (warn_count > 0) { printf(" %ld Warnings Issued\n", warn_count); } /* end if */ if (err_count > 0) { printf(" %d Errors Detected\n\n", err_count); return -1; } /* end if */ return 0; } /* end main */ /***********************************************************************/ void openNestedFile(const char *fileName) { fileState_t *prev = FP; char fullpath[FNAME_SIZE + 1]; int i; /* Make sure we can handle another nested file */ if (++includeIndex >= MAX_INCL) fatal(eOVF); else { /* Clear the file state structure for the new include level */ memset(FP, 0, sizeof(fileState_t)); /* Try all source include pathes until we find the file or * until we exhaust the include path list. */ for (i = 0; ; i++) { /* Open the nested file -- try all possible pathes or * until we successfully open the file. */ /* The final path that we will try is the current directory */ if (i == nIncPathes) { sprintf(fullpath, "./%s", fileName); } else { sprintf(fullpath, "%s/%s", includePath[i], fileName); } FP->stream = fopen (fullpath, "rb"); if (!FP->stream) { /* We failed to open the file. If there are no more * include pathes to examine (including the current directory), * then error out. This is fatal. Otherwise, continue * looping. */ if (i == nIncPathes) { errmsg("Failed to open '%s': %s\n", fileName, strerror(errno)); fatal(eINCLUDE); break; /* Won't get here */ } } /* end else if */ else break; } /* Setup the newly opened file */ fprintf(errFile, "%01x=%s\n", FP->include, fullpath); FP->include = poffAddFileName(poffHandle, fullpath); /* The caller may change this, but the default behavior is * to inherit the kind and section of the including file * and the current data stack offset. */ FP->kind = prev->kind; FP->section = prev->section; FP->dstack = dstack; rePrimeTokenizer(); /* Get the first token from the file */ getToken(); } /* end else */ } /***********************************************************************/ void closeNestedFile(void) { if (FP->stream) { (void)fclose(FP->stream); includeIndex--; } } /***********************************************************************/