view anagram/agcore/operations.cpp @ 21:1c9dac05d040

Add lint-style FALLTHROUGH annotations to fallthrough cases. (in the parse engine and thus the output code) Document this, because the old output causes warnings with gcc10.
author David A. Holland
date Mon, 13 Jun 2022 00:04:38 -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;
}