Mercurial > ~dholland > hg > ag > index.cgi
diff anagram/agcore/operations.cpp @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/anagram/agcore/operations.cpp Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,375 @@ +/* + * AnaGram, A System for Syntax Directed Programming + * Copyright 1993-2002 Parsifal Software. All Rights Reserved. + * Copyright 2006 David A. Holland. All Rights Reserved. + * See the file COPYING for license and usage terms. + * + * operations.cpp - central operations + */ + +#ifdef AG_ON_UNIX +#include <sys/types.h> +#include <sys/param.h> // for MAXPATHLEN (see below) +#endif + +#ifdef AG_ON_WINDOWS +#include <windows.h> // for HMODULE and GetModuleFileName +#endif + +#include "port.h" + +#ifdef VACLGUI +//#include <imsgbox.hpp> +#include "action.h" +#endif + +#include "agdict.h" +#include "aglib.h" +#include "agstring.h" +#include "assert.h" +#include "bpe3.h" +#include "bpu.h" +#include "cf-defs.h" +#include "checksum.h" +#include "config.h" +#include "configparam.h" +#include "data.h" +#include "engdef.h" +#include "error.h" +#include "file.h" +#include "ftpar.h" +#include "keyword.h" +#include "operations.h" +#include "p.h" +#include "q1a.h" +#include "rproc.h" +#include "rule.h" +#include "stacks.h" +#include "sums-defs.h" +#include "symbol.h" +#include "token.h" +#include "tree.h" +#include "textfile.h" + +//#define INCLUDE_LOGGING +#include "log.h" + + +/* +extern int bytesAllocated; +extern int constructorCalls; +extern int copyConstructorCalls; +extern int destructorCalls; + +extern int nodesCreated; +extern int nodesDeleted; +extern int nodesAllocated; +extern int nodesFreed; + +extern int myallocs; +extern int myfrees; +extern int myallocBytes; +extern int myfreeBytes; +extern int arrayBytesAllocated; +extern int arrayBytesFreed; +extern int arraysAllocated; +extern int arraysFreed; + +extern int newCalls; +extern int newArrayCalls; +extern int deleteCalls; +extern int deleteArrayCalls; + +extern int dcsCreated; +extern int dcsDestroyed; +extern int sconConstructorCalls; +extern int sconDestructorCalls; +*/ + + +static unsigned n_config_errors; + +// XXX does this really accomplish anything? +#ifdef VACLGUI +static AgAction startAction; +#endif + +unsigned char *input_base; +static AgString my_own_dir; + + +/* first thing that happens; comes from main() */ +void init(char *argv_0) { + LOGINIT(); + LOGSECTION("init"); + LOGV(argv_0); + +#ifdef AG_ON_WINDOWS + /* Is this necessary or even useful? */ + char buf[MAX_PATH]; + //_fullpath(buf, argv_0, MAX_PATH); + HMODULE module = GetModuleHandle(0); + GetModuleFileName(module, buf, MAX_PATH); + LOGV(buf); + argv_0 = buf; +#endif + +#ifdef AG_ON_UNIX + // realpath is documented with MAXPATHLEN from sys/param.h, not + // PATH_MAX from limits.h. + // + // I don't think there are systems where these are different, but + // never underestimate the power of stupidity when people decide + // to release their very own System-V-derived Buggix. + // + //char buf[PATH_MAX]; + char buf[MAXPATHLEN]; + if (realpath(argv_0, buf) != NULL) { + LOGV(buf); + argv_0 = buf; + } +#endif + + sum_remember_argv0(argv_0); + + AgString myself = argv_0; + my_own_dir = myself.lastCut(PATH_DELIMITER).leftX(); +} + +void init_parser(void) { + LOGSECTION("init_parser"); + no_assertions = 0; + + init_stk(); + init_data(); + Cast::reset(); + Symbol::reset(); + Token::reset(); + set_work_dir(); + read_config(my_own_dir); + ConfigParam::initAll(); + + n_config_errors = errorList.size(); //nerrors; + reset_parser(); +} + +#if 0 /* NOT USED */ +int netAllocations() { + return newArrayCalls - deleteArrayCalls + + newCalls - deleteCalls + - (arraysAllocated - arraysFreed); +} +#endif + +#if 0 /* NOT USED */ +void logAlloc() { + LOGV(bytesAllocated) LCV(constructorCalls) LCV(copyConstructorCalls) + LCV(destructorCalls); + LOGV(nodesCreated - nodesDeleted); + LOGV(newArrayCalls) LCV(deleteArrayCalls) LCV(newCalls) LCV(deleteCalls); + LOGV(myallocs - myfrees) LCV(myallocBytes- myfreeBytes); + LOGV(newArrayCalls - deleteArrayCalls) LCV(newCalls - deleteCalls); + LOGV(arraysAllocated - arraysFreed) + LCV(arrayBytesAllocated - arrayBytesFreed); + // note: this line wasn't in agsa.cpp, only main.cpp + LOGV(dcsCreated) LCV(dcsDestroyed) + LCV(sconConstructorCalls) LCV(sconDestructorCalls); +} +#endif + +void reset_parser(void) { + LOGSECTION("reset_parser"); + if (syntax_state == syntax_reset) { + return; + } + syntax_state = syntax_reset; +#if 0 + logAlloc(); +#endif + reset_result_data(); + LOGS("result data reset"); + reset_summary_data(); + LOGS("summary data reset"); + cSegmentStack.reset(); + LOGS("cSegmentStack reset"); + extensionStack.reset(); + LOGS("extenstionStack.reset"); + cVariableList.reset(); + LOGS("cVariablelist reset"); + //errorList.reset(); + traceCounts.reset(); + LOGS("traceCounts reset"); + valueToken.reset(); + LOGS("valueToken reset"); + + Cast::reset(); + LOGS("Cast reset"); + Keyword::reset(); + LOGS("Keyword reset"); + ParseTree::reset(); + LOGS("ParseTree reset"); + Procedure::reset(); + Rule::reset(); + //State::reset(); + Symbol::reset(); + Token::reset(); + // note: the following line was not in agsa.cpp, only main.cpp. + // but I suspect that was a bug... + VpRule::reset(); + + LOGS("Tables reset"); + ConfigParam::resetAll(); + nPrologueSegments = 0; +} + +void analyzeGrammar(AgString data, int hasGui) { + LOGSECTION("analyzeGrammar"); + reset_parser(); + input_base = (unsigned char *) data.pointer(); + syntax_state = syntax_loaded; + syntax_error_flag = parse_abort_flag = 0; + badRecursionFlag = 0; + scan_input(); + LOGS("input scan complete"); + if (badRecursionFlag && hasGui) { + ssprintf("File Trace disabled: %s", badRecursionFlag); + log_error(); + } + if (syntax_error_flag || + parse_abort_flag || + nprods == 0 || + grammar_token == 0 || + //badRecursionFlag || + syntax_state != syntax_parsed) { + return; + } + new_syntax_analyzer(); + assert(int_stack_top == 0); + assert(nc == 0); + assert(nw == 0); +} + +void buildParser() { + LOGSECTION("Build parser"); + LOGV(syntax_state); + if (syntax_state == syntax_analyzed) { + LOGS("build engine"); + *buildErrorMsg = 0; + build_parse_engine(); + if (*buildErrorMsg) { + errorList.push(Error(buildErrorMsg)); + } + LOGS("build complete"); + syntax_state = engine_built; + } + assert(int_stack_top == 0); + assert(nc == 0); + assert(nw == 0); +} + +static void dump_errors() { + LOGSECTION("dump_errors"); + unsigned i; + + LOGV(errorList.size()); + for (i = 0; i < errorList.size(); i++) { + Error &e = errorList[i]; + LOGV(i) LCV(e.line) LCV(e.column); + LOGV(e.file.pointer()); + LOGV((int) e.key) LCV(Error::keyString[e.key]); + // XXX if AG_ON_UNIX should default to gcc's format, and go to stderr + printf("%s(%d-%d): %s: %s\n", + e.file.pointer(), e.line, e.column, + Error::keyString[e.key], e.message.pointer()); + } + fflush(stdout); +} + +static text_file buildFile; + +static void doBuild(void) { + if (buildFile.text.exists()) { + analyzeGrammar(buildFile.text, 0 /* no GUI */); + buildParser(); + } + else { + ssprintf("Cannot read %s",infile_name.pointer()); + log_error(); + errorList.top().setFatal(); + } + if (errorList.size()) { + dump_errors(); + } +} + +int commandLineBuild(char *n) { + LOGSECTION("commandLineBuild"); + + //AgString path(fp); + engdef_init(); + init_parser(); + const char *failure = checksums_ok(); + if (failure) { + fprintf(stderr, "Initialization failure: %s\n", failure); + AgString whine = code_segment("broken").pointer(); + fprintf(stderr, "%s\n", whine.pointer()); + return 1; + } + + AgString name(n); + LOGV(name); + + // XXX. Does this really need to be conditional? +#ifdef VACLGUI + startAction = actionObject(doBuild); +#endif + +#ifdef AG_ON_WINDOWS + AgString fullpath(_MAX_PATH); + _fullpath(fullpath.pointer(), name.pointer(), _MAX_PATH); + AgString fileName = fullpath.lastCut("\\/:").rightX(); +#endif + +#ifdef AG_ON_UNIX +#if 0 /* Don't use realpath; it's not the canonical Unix way */ + // realpath is documented to use MAXPATHLEN, not PATH_MAX. sigh. + // (see longer comment above) + //AgString fullpath(PATH_MAX); + AgString fullpath(MAXPATHLEN); + + realpath(name.pointer(), fullpath.pointer()); + AgString fileName = fullpath.lastCut('/').rightX(); +#else + AgString fullpath = name; + AgString fileName = fullpath.lastCut('/').rightX(); + if (fileName.size() == 0) { + fileName = fullpath; + } +#endif /* 0 */ +#endif /* AG_ON_UNIX */ + + infile_name = fullpath; // Store selected file name + errorReportFile = infile_name; // Store selected file name + + simple_file_name = fileName.lastCut('.').leftX(); + + LOGV(fileName.pointer()); + LOGV(simple_file_name.pointer()); + text_file inputFile(infile_name); + + if (!inputFile.text.exists() && fileName == simple_file_name) { + infile_name = infile_name.concat(".syn"); + inputFile = text_file(infile_name); + LOGV(infile_name.pointer()); + } + buildFile = inputFile; + + // XXX as above +#ifdef VACLGUI + startAction(); +#else + doBuild(); +#endif + + return syntax_state != engine_built; +}