view examples/mpp/ex.syn @ 14:a02e9434072e

Fix friend declaration for gcc10. XXX: did not check it against the IBM compiler, might end up needing XXX: to be conditional.
author David A. Holland
date Tue, 31 May 2022 00:59:42 -0400
parents 13d2b8934445
children
line wrap: on
line source

{
/*
 * AnaGram, a System for Syntax Directed Programming
 * C Macro preprocessor
 * Constant Expression Evaluator Module
 *
 * 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.
 */

#include "mpp.h"
}

[
  //far tables                             // uncomment for 16 bit environment
 ~allow macros
  line numbers
  //escape backslashes                     // uncomment if using MSVC++
  default token type = long
  default input type = token
 ~declare pcb
 ~diagnose errors
  error trace
  event driven
  input values
 ~test range
 ~lines and columns
  enum {
    eof               =0,
    SPACE             =' ',
    ANDAND            ='A', // "&&"
    ANDassign,              // "&="
    ARROW,                  // "->"
    CONCAT,                 // "##"
    DECR,                   // "--"
    DIVassign,              // "/="
    ELLIPSIS,               // "..."
    EQ,                     // "=="
    ERassign,               // "^="
    GE,                     // ">="
    ICR,                    // "++"
    LE,                     // "<="
    LS,                     // "<<"
    LSassign,               // "<<="
    MODassign,              // "%="
    MINUSassign,            // "-="
    MULTassign,             // "*="
    NE,                     // "!="
    ORassign,               // "|="
    OROR,                   // "||"
    PLUSassign,             // "+="
    RS,                     // ">>"
    RSassign,               // ">>="
    CHARACTERconstant,      // character constant
    STRINGliteral,          // character string
    HEXconstant       =129,
    OCTconstant,
    DECconstant,
    FLOATconstant,          // real
    NAME,
    AUTO,                   // "auto"
    BREAK,                  // "break"
    CASE,                   // "case"
    CHAR,                   // "char"
    CONSTANT,               // "const"
    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"
    VOIDkey,                // "void"
    VOLATILE,               // "volatile"
    WHILE,                  // "while"
    UNRECOGNIZED,
  }
  parser file name = "#.cpp"
]

expression evaluator $
 -> exp, eof

exp
 -> conditional exp

conditional exp
 -> logical or exp
 -> logical or exp:c, '?', conditional exp:x, ':',
    conditional exp:y                                  = c != 0 ? x : y;

logical or exp
 -> logical and exp
 -> logical or exp:x, OROR, logical and exp:y          =x != 0 || y!=0;

logical and exp
 -> inclusive or exp
 -> logical and exp:x, ANDAND, inclusive or exp:y      =x != 0 && y !=0;

inclusive or exp
 -> exclusive or exp
 -> inclusive or exp:x, '|', exclusive or exp:y        =x | y;

exclusive or exp
 -> and exp
 -> exclusive or exp:x, '^', and exp:y                 =x ^ y;

and exp
 -> equality exp
 -> and exp:x, '&', equality exp:y                     =x & y;

equality exp
 -> relational exp
 -> equality exp:x, EQ, relational exp:y               =x == y;
 -> equality exp:x, NE, relational exp:y               =x != y;

relational exp
 -> shift exp
 -> relational exp:x, '<', shift exp:y                 =x < y;
 -> relational exp:x, '>', shift exp:y                 =x > y;
 -> relational exp:x, LE, shift exp:y                  =x <= y;
 -> relational exp:x, GE, shift exp:y                  =x >= y;

shift exp
 -> additive exp
 -> shift exp:x, LS, additive exp:y                    =x << y;
 -> shift exp:x, RS, additive exp:y                    =x >> y;

additive exp
 -> multiplicative exp
 -> additive exp:x, '+', multiplicative exp:y          =x + y;
 -> additive exp:x, '-', multiplicative exp:y          =x - y;

multiplicative exp
 -> unary exp
 -> multiplicative exp:x, '*', unary exp:y             =x * y;
 -> multiplicative exp:x, '/', nonzero:y               =x / y;
 -> multiplicative exp:x, '%', nonzero:y               =x % y;

nonzero
  -> unary exp: x ={
      if (x != 0) return x;
      syntax_error("Divide by Zero");
      PCB.exit_flag = 5;
      return x;
    }

unary exp
 -> primary exp
 -> '+', unary exp:x            = x;
 -> '-', unary exp:x            = -x;
 -> '~', unary exp:x            = ~x;
 -> '!', unary exp:x            = !x;

primary exp
 -> HEXconstant:x               =decode("%lx",x.handle);
 -> OCTconstant:x               =decode("%lo",x.handle);
 -> DECconstant:x               =decode("%ld",x.handle);
 -> CHARACTERconstant:x         =decode("'%lc'",x.handle);
 -> NAME                        =0;
 -> '(', conditional exp:x, ')' =x;


{                                      // Embedded C
#include <stdio.h>


// Macro Definitions

#define PCB (*ex_pcb)
#define SYNTAX_ERROR syntax_error("Syntax error in constant expression");


// Static data

static ex_pcb_type *ex_pcb;            // Pointer to active pcb


/*

decode() is a simple function to recover the numeric value of a
token. Its task is somewhat simplified by the fact that the only
values allowed in this example are longs.

*/

static long decode(const char *fmt, unsigned ndx) {
  long v;
  sscanf(td[ndx], fmt, &v);
  return v;
}


// Members of expression_evaluator Class


// Constructor

/*
  Each expression_evaluator has its own parser control block.
  Therefore, before calling ex() or its initializer init_ex() it is
  necessary to make sure the pcb pointer for ex() is correctly set.
*/

expression_evaluator::expression_evaluator() {
  ex_pcb = &pcb;                       // set up pointer to pcb
  init_ex();                           // init parser
}


// Reset expression_evaluator

token_sink& reset(expression_evaluator &x) {
  ex_pcb = &x.pcb;                     // set up pointer to pcb
  init_ex();                           // init parser
  return x;
}


// Xmit Token to expression_evaluator

/*
  There could be space tokens in the input to the expression
  evaluator, but they are never significant so it is acceptable to
  filter them out on input.

  If the expression_evaluator has encountered an error, there is no
  point in giving it any further input.

  Otherwise, the input_code and input_value fields of the pcb are set
  up, the pcb pointer for ex is set, and ex() is called to deal with
  the token.

  When looping, it is only necessary to set up ex_pcb at the
  beginning of the loop.
*/

token_sink& expression_evaluator::operator << (token t) {
  if (t.id == SPACE || pcb.exit_flag != AG_RUNNING_CODE) return *this;
  pcb.input_code = t.id;
  pcb.input_value = t;
  ex_pcb = &pcb;
  ex();
  return *this;
}

token_sink &expression_evaluator::operator << (token *tp) {
  ex_pcb = &pcb;
  while (pcb.exit_flag == AG_RUNNING_CODE) {
    if (pcb.input_code == SPACE) continue;
    pcb.input_code = tp->id;
    pcb.input_value = *tp++;
    ex();
  }
  return *this;
}


// Return Value of expression_evaluator

/*
  The (long) cast operator is overloaded to provide a mechanism to
  retrieve the value of the expression evaluated by the
  expression_evaluator.

  If there was a syntax error, the return value is zero.
*/

expression_evaluator::operator long() {
  ex_pcb = &pcb;
  if (pcb.exit_flag == AG_SUCCESS_CODE) return ex_value();
  else return 0;
}

/*
// Check expression_evaluator for error

int error(expression_evaluator &x) {
  return x.pcb.exit_flag != AG_SUCCESS_CODE;
}
*/
}                                      // End of Embedded C