view examples/mpp/mpp.cpp @ 4:bebb2ba69e1d

maybe help with getting tex to fail properly on error
author David A. Holland
date Sat, 18 Apr 2020 17:12:17 -0400
parents 13d2b8934445
children
line wrap: on
line source

/*
 * AnaGram, a System for Syntax Directed Programming
 * C Macro preprocessor
 * Global Data and Main Program
 *
 * Copyright 1993-2000 Parsifal Software. All Rights Reserved.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

// for out of date compilers
#if defined(__IBMCPP__)
#define OLDCPLUSPLUS
#endif

#include "mpp.h"
#include <stdlib.h>
#include <ctype.h>

#ifdef OLDCPLUSPLUS
#include <new.h>
#else
#include <new>
#endif

#include "array.h"               // \ANAGRAM\CLASSLIB\INCLUDE\ARRAY.H
#include "util.h"                // \ANAGRAM\CLASSLIB\INCLUDE\UTIL.H


// Global data definitions

expression_evaluator   condition;
unsigned               defined_value;
int                    if_clause = 0;
char                   default_path[] = ""; //default include file path, if desired
macro_descriptor       macro[N_MACROS];
unsigned               macro_id[N_SYMBOLS] = {0};
int                    n_macros = 0;
unsigned               n_reserved_words = 0;
int                    nest_comments = 0;
unsigned               one_value;
stack<char *>          paths(20,1);
string_accumulator     sa(1000,20);
token_sink            *scanner_sink;
token_accumulator      ta(1000,20);
string_dictionary      td(N_SYMBOLS);
unsigned               token_handles[256];
unsigned               zero_value;


// Initialization data

op_descriptor ops[] = {
  {"&&"       , ANDAND},
  {"&="       , ANDassign},
  {"->"       , ARROW},
  {"##"       , CONCAT},
  {"--"       , DECR},
  {"/="       , DIVassign},
  {"..."      , ELLIPSIS},
  {"=="       , EQ},
  {"^="       , ERassign},
  {">="       , GE},
  {"++"       , ICR},
  {"<="       , LE},
  {"<<"       , LS},
  {"<<="      , LSassign},
  {"%="       , MODassign},
  {"-="       , MINUSassign},
  {"*="       , MULTassign},
  {"!="       , NE},
  {"|="       , ORassign},
  {"||"       , OROR},
  {"+="       , PLUSassign},
  {">>"       , RS},
  {">>="      , RSassign},
  {" "        , SPACE},
};

op_descriptor reserved_words[] = {
  {NULL,        END_OF_FILE },
  {"auto",      AUTO        },
  {"break",     BREAK       },
  {"case",      CASE        },
  {"char",      CHAR        },
  {"const",     CONSTANT    },
  {"continue",  CONTINUE    },
  {"default",   DEFAULT     },
  {"do",        DO          },
  {"double",    DOUBLE      },
  {"else",      ELSE        },
  {"enum",      ENUM        },
  {"extern",    EXTERN      },
  {"float",     FLOAT       },
  {"for",       FOR         },
  {"goto",      GOTO        },
  {"if",        IF          },
  {"int",       INT         },
  {"long",      LONG        },
  {"register",  REGISTER    },
  {"return",    RETURN      },
  {"short",     SHORT       },
  {"signed",    SIGNED      },
  {"sizeof",    SIZEOF      },
  {"static",    STATIC      },
  {"struct",    STRUCT      },
  {"switch",    SWITCH      },
  {"typedef",   TYPEDEF     },
  {"union",     UNION       },
  {"unsigned",  UNSIGNED    },
  {"void",      VOIDkey     },
  {"volatile",  VOLATILE    },
  {"while",     WHILE       },
};


// Data initializer

static void init_data(void) {
  unsigned k;

  memset(token_handles, 0, 256*sizeof(unsigned));

  n_reserved_words = sizeof(reserved_words) / sizeof(op_descriptor);

  assert(size(td) == 0);

  for (k = 1; k < n_reserved_words; k++) {
    unsigned index = td << reserved_words[k].op;
    token_handles[reserved_words[k].id] = index;
    assert(index == k);
  }

  k = sizeof(ops) / sizeof(op_descriptor);
  while (k--) token_handles[ops[k].id] = td << ops[k].op;

  for (k = 1; k < 127; k++) {
    if (token_handles[k] || isalnum(k)) continue;
    token_handles[k] = td << (char *) &k;
  }

  defined_value = td << "defined";
  one_value = td << "1";
  zero_value = td << "0";
}


// Field memory allocation failures

#if defined(OLDCPLUSPLUS) && defined(_MSC_VER)
// Cope with peculiarity of MSVC++
// (probably not needed any more - someone with a recent MSVC please advise)
static int out_of_space(size_t) {
  printf("\nOut of space\n");
  exit(1);
  // Cookie for the cookie monster
  return 0;
}
#else
static void out_of_space(void) {
  printf("\nOut of space\n");
  exit(1);
}
#endif

// Extract and directory names from path statement

static void extract_paths(const char *path_string) {
  if (path_string == NULL) return;   // exit if no default paths
  ++sa << path_string;               // temporary copy of path string
  char *p = sa.top();                // init scan pointer
  char *q = strrchr(p,';');          // look for rightmost semi-colon
  while (q != NULL) {
    *q++ = 0;                        // replace it with null
    while (*q == ' ') q++;           // skip over blanks
    paths << memdup(q, 1+strlen(q)); // stack copy
    q = strrchr(p, ';');
  }
  while (*p == ' ') p++;             // get rid of blanks
  paths << memdup(p, 1+strlen(p));   // stack last path
  --sa;
}


// Main Program

int main(int argc, char *argv[]) {
  int i;                              // for indexing args
  c_parser cp;                        // initialize c parser
  char *inpath = NULL;                // input file name
  char *outpath = NULL;               // output file name

#if defined(OLDCPLUSPLUS)
#ifdef _MSC_VER                       //Cope with peculiarity of MSVC++
  _set_new_handler(out_of_space);     // field allocation errors
#else
  set_new_handler(out_of_space);      // field allocation errors
#endif
#else /* current standard C++ dialect */
  std::set_new_handler(out_of_space); // field allocation errors
#endif
  init_data();                        // initialize data

  extract_paths(default_path);        // get default include directories

  for (i = 1; i < argc; i++) {
    switch (*argv[i]) {
      case '-':
      case '/':
        switch (argv[i][1]) {
          case 'c':
            scanner_sink = &cp;       // output to c parser
            break;
          case 'n':
            nest_comments = 1;        // accept nested comments
            break;
          case 'i':
            extract_paths(argv[i] + 2); // include path
            break;
          default:
            printf("Unrecognized switch: %c\n", argv[i][1]);
        }
        continue;
    }
    break;
  }

  extract_paths("./");                // add local directory to include paths

  assert(i < argc);                   // there always has to be an input
  inpath = argv[i++];

  if (i < argc) outpath = argv[i++];  // output file specified?
  else outpath = NULL;

  output_file file(outpath);          // open output file
  token_translator tt(&file);         // set up translator

  if (scanner_sink == NULL)           // if compiler not selected
    scanner_sink = &tt;               // output to token translator

  scan_input(inpath);                 // do it!  (see TS.SYN)
  return 0;
}