view anagram/agcore/operations.cpp @ 12:aab9ff6af791

Strengthen the build hack for non-DOS targets.
author David A. Holland
date Tue, 31 May 2022 00:58:42 -0400
parents 13d2b8934445
children
line wrap: on
line source

/*
 * 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;
}