view examples/mpp/mpp.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
 * 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;
}