Note: jamexp.y uses GNU extensions of the YACC grammar as defined by GNU bison

Reverse-engineering steps and inputs:

* Write a unit test program (driver jamexp_gen.c) using a jamexp.c generated
  from jamexp.y with bison and the test functions in jamexp_shrd.c

** Copy old jamexp.c to jamexp.y, remove generated tables and replace with
   directives for the Bison parser generator.
** Use operator precedences from the Stapl specification [1] and the grammar
   of the C language [2] to derive the grammar for the Stapl expression parser.
** Fix grammar errors by comparing the parser debug outputs with corresponding
   outputs of the test driver for the non-generated jamexp.c
** Repeat until all tests succeed.

[1] http://www.jtagtest.com/pdf/jesd71_stapl.pdf
[2] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

Integration hints:

* must be compiled as a 32-bit executable ('gcc -m32' was used)
* 'export URJ_JAM_YYDEBUG=1' before calling the test driver will
  generate parser debug information

* CPP options:

** -DURJ_JAM_YYDEBUG=1 # debug output from $(BISON_OUT_DIR)/jamexp.c
** --include config.h
** -Iinclude           # "urjtag/gettext.h"
** -Isrc/stapl
** -Itests/stapl
** -I.                 # "tests/tap/macros.h" in tests/tap/basic.c/basic.h
** -I($BISON_OUT_DIR)

* Bison options:

** --report=all --warnings=all --debug --defines=$(BISON_OUT_DIR)/jamytab.h

* Source files:

** tests/stapl/jamexp_gen.c     # defines main()
** src/stapl/jamarray.c
** src/stapl/jamcomp.c
** src/stapl/jamexec.c
** $(BISON_OUT_DIR)/jamexp.c
** src/stapl/jamheap.c
** src/stapl/jamjtag.c
** src/stapl/jamstack.c
** src/stapl/jamsym.c
** tests/stapl/jamexp_shrd.c
** tests/tap/basic.c

* Libraries:
** libm

Signed-off-by: Peter Pöschl <pp+ujt2...@nest-ai.de>
---
 urjtag/src/stapl/jamexp.y       | 1556 +++++++++++++++++++++++++++++++
 urjtag/tests/stapl/jamexp_gen.c |   35 +
 2 files changed, 1591 insertions(+)
 create mode 100644 urjtag/src/stapl/jamexp.y
 create mode 100644 urjtag/tests/stapl/jamexp_gen.c

diff --git a/urjtag/src/stapl/jamexp.y b/urjtag/src/stapl/jamexp.y
new file mode 100644
index 00000000..47f6af4d
--- /dev/null
+++ b/urjtag/src/stapl/jamexp.y
@@ -0,0 +1,1556 @@
+// SPDX-FileCopyrightText: 1997 Altera Corporation
+// SPDX-FileCopyrightText: 2022 Peter Poeschl <pp+ujt2...@nest-ai.de>
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+%code top {
+#include <stdint.h>
+#include <stdio.h>
+#include <math.h>
+#include "jamexprt.h"
+#include "jamdefs.h"
+#include "jamexp.h"
+#include "jamsym.h"
+#include "jamheap.h"
+#include "jamarray.h"
+#include "jamutil.h"
+#include "jamytab.h"
+}
+
+%code {
+/* ------------- LEXER DEFINITIONS -----------------------------------------*/
+/****************************************************************************/
+/*                                                                          */
+/*  Operation of GET_FIRST_CH, GET_NEXT_CH, UNGET_CH, and DELETE_CH:        */
+/*                                                                          */
+/*  Call GET_FIRST_CH to read a character from mdl_lexer_fp and put it into */
+/*  urj_jam_ch and urj_jam_token_buffer.                                    */
+/*                                                                          */
+/*      urj_jam_ch = first char                                             */
+/*      urj_jam_token_buffer[0] = first char                                */
+/*      urj_jam_token_buffer[1] = '\0';                                     */
+/*      urj_jam_token_buffer[2] = ?                                         */
+/*      urj_jam_token_buffer[3] = ?                                         */
+/*                                                                          */
+/*  Call GET_NEXT_CH to read a character from jam_lexer_fp, put it in       */
+/*  urj_jam_ch, and append it to urj_jam_token_buffer.                      */
+/*                                                                          */
+/*      urj_jam_ch = second char                                            */
+/*      urj_jam_token_buffer[0] = first char                                */
+/*      urj_jam_token_buffer[1] = second char                               */
+/*      urj_jam_token_buffer[2] = '\0';                                     */
+/*      urj_jam_token_buffer[3] = ?                                         */
+/*                                                                          */
+/*  Call UNGET_CH remove the last character from the buffer but leave it in */
+/*  urj_jam_ch and set a flag.  (The next call to GET_FIRST_CH will use     */
+/*  urj_jam_ch as the first char of the token and clear the flag.)          */
+/*                                                                          */
+/*      urj_jam_ch = second char                                            */
+/*      urj_jam_token_buffer[0] = first char                                */
+/*      urj_jam_token_buffer[1] = '\0';                                     */
+/*      urj_jam_token_buffer[2] = ?                                         */
+/*      urj_jam_token_buffer[3] = ?                                         */
+/*                                                                          */
+/*  Call DELETE_CH to remove the last character from the buffer.  Use this  */
+/*  macro to discard the quotes surrounding a string, for example.  Unlike  */
+/*  UNGET_CH, the deleted character will not be reused.                     */
+/*                                                                          */
+/****************************************************************************/
+
+#define MAX_BUFFER_LENGTH   1024
+#define END_OF_STRING       -1
+
+
+
+/****************************************************************************/
+/*                                                                          */
+/*  Operation of BEGIN_MACHINE, END_MACHINE, and ACCEPT:                    */
+/*                                                                          */
+/*  BEGIN_MACHINE and END_MACHINE should be at the beginning the end of an  */
+/*  integer function.  Inside the function, define states of the machine    */
+/*  with normal C labels, and jump to states with normal C goto statements. */
+/*  Use ACCEPT(token) to return an integer value token to the calling       */
+/*  routine.                                                                */
+/*                                                                          */
+/*      int foo (void)                                                      */
+/*      {                                                                   */
+/*          BEGIN_MACHINE;                                                  */
+/*                                                                          */
+/*          start:                                                          */
+/*              if (whatever) goto next;                                    */
+/*              else goto start;                                            */
+/*                                                                          */
+/*          next:                                                           */
+/*              if (done) ACCEPT (a_token_id);                              */
+/*              else goto start;                                            */
+/*                                                                          */
+/*          END_MACHINE;                                                    */
+/*      }                                                                   */
+/*                                                                          */
+/*  Be sure that there is an ACCEPT() or goto at the end of every state.    */
+/*  Otherwise, control will "flow" from one state to the next illegally.    */
+/*                                                                          */
+/****************************************************************************/
+
+#define BEGIN_MACHINE   {int ret
+
+#define ACCEPT(token)   {ret = (token); goto accept;}
+
+#define END_MACHINE     accept: urj_jam_token = ret; \
+                        }
+// need defines, single-chars cannot be %token
+#define GREATER_TOK '>'
+#define LESS_TOK    '<'
+
+struct
+{
+    char *string;
+    int length;
+    int token;
+} static const jam_keyword_table[] =
+{
+    {"&&", 2, AND_TOK},
+    {"||", 2, OR_TOK},
+    {"==", 2, EQUALITY_TOK},
+    {"!=", 2, INEQUALITY_TOK},
+    {">", 2, GREATER_TOK},
+    {"<", 2, LESS_TOK},
+    {">=", 2, GREATER_EQ_TOK},
+    {"<=", 2, LESS_OR_EQ_TOK},
+    {"<<", 2, LEFT_SHIFT_TOK},
+    {">>", 2, RIGHT_SHIFT_TOK},
+    {"..", 2, DOT_DOT_TOK},
+    {"OR", 2, OR_TOK},
+    {"AND", 3, AND_TOK},
+    {"ABS", 3, ABS_TOK},
+    {"INT", 3, INT_TOK},
+    {"LOG2", 4, LOG2_TOK},
+    {"SQRT", 4, SQRT_TOK},
+    {"CEIL", 4, CIEL_TOK},
+    {"FLOOR", 5, FLOOR_TOK}
+};
+
+char urj_jam_ch = '\0';             /* next character from input file */
+int urj_jam_strptr = 0;
+int urj_jam_token = 0;
+char urj_jam_token_buffer[MAX_BUFFER_LENGTH];
+int urj_jam_token_buffer_index;
+char urj_jam_parse_string[MAX_BUFFER_LENGTH];
+int32_t urj_jam_parse_value = 0;
+int urj_jam_expression_type = 0;
+JAMS_SYMBOL_RECORD *urj_jam_array_symbol_rec = NULL;
+
+#define YYMAXDEPTH 300          /* This fixes a stack depth problem on  */
+                        /* all platforms.                       */
+
+#define YYMAXTLIST 25           /* Max valid next tokens for any state. */
+                        /* If there are more, error reporting   */
+                        /* will be incomplete.                  */
+
+}
+
+%code requires {
+enum OPERATOR_TYPE
+{
+    ADD = 0,
+    SUB,
+    UMINUS,
+    MULT,
+    DIV,
+    MOD,
+    NOT,
+    AND,
+    OR,
+    BITWISE_NOT,
+    BITWISE_AND,
+    BITWISE_OR,
+    BITWISE_XOR,
+    LEFT_SHIFT,
+    RIGHT_SHIFT,
+    DOT_DOT,
+    EQUALITY,
+    INEQUALITY,
+    GREATER_THAN,
+    LESS_THAN,
+    GREATER_OR_EQUAL,
+    LESS_OR_EQUAL,
+    ABS,
+    INT,
+    LOG2,
+    SQRT,
+    CIEL,
+    FLOOR,
+    ARRAY,
+    POUND,
+    DOLLAR,
+    ARRAY_RANGE,
+    ARRAY_ALL
+};
+
+typedef enum OPERATOR_TYPE OPERATOR_TYPE;
+
+typedef struct EXP_STACK
+{
+    OPERATOR_TYPE child_otype;
+    JAME_EXPRESSION_TYPE type;
+    int32_t val;
+    int32_t loper;              /* left and right operands for DIV */
+    int32_t roper;              /* we save it for CEIL/FLOOR's use */
+} EXPN_STACK;
+
+#define URJ_JAM_YYSTYPE EXPN_STACK      /* must be a #define for yacc */
+}
+
+%code {
+YYSTYPE urj_jam_null_expression = { 0, 0, 0, 0, 0 };
+
+JAM_RETURN_TYPE urj_jam_return_code = JAMC_SUCCESS;
+
+JAME_EXPRESSION_TYPE urj_jam_expr_type = JAM_ILLEGAL_EXPR_TYPE;
+
+#define NULL_EXP urj_jam_null_expression    /* .. for 1 operand operators */
+
+#define CALC(operator, lval, rval) urj_jam_exp_eval((operator), (lval), (rval))
+}
+
+%code provides {
+/* --- FUNCTION PROTOTYPES -------------------------------------------- */
+
+int urj_jam_yyparse (void);
+int urj_jam_yylex (void);
+}
+
+%code {
+#ifdef DELME_OLD_TOKEN_VALUES
+#define AND_TOK 257
+#define OR_TOK 258
+#define EQUALITY_TOK 259
+#define INEQUALITY_TOK 260
+#define GREATER_TOK 261
+#define LESS_TOK 262
+#define GREATER_EQ_TOK 263
+#define LESS_OR_EQ_TOK 264
+#define LEFT_SHIFT_TOK 265
+#define RIGHT_SHIFT_TOK 266
+#define DOT_DOT_TOK 267
+#define ABS_TOK 268
+#define INT_TOK 269
+#define LOG2_TOK 270
+#define SQRT_TOK 271
+#define CIEL_TOK 272
+#define FLOOR_TOK 273
+#define VALUE_TOK 274
+#define IDENTIFIER_TOK 275
+#define ARRAY_TOK 276
+#define ERROR_TOK 277
+#define UNARY_MINUS 278
+#define UNARY_PLUS 279
+#endif // DELME_OLD_TOKEN_VALUES
+
+YYSTYPE urj_jam_yylval, urj_jam_yyval;
+int32_t urj_jam_convert_bool_to_int (int32_t *data, int32_t msb, int32_t lsb);
+EXPN_STACK urj_jam_exp_eval (OPERATOR_TYPE otype, EXPN_STACK op1, EXPN_STACK 
op2);
+void urj_jam_exp_lexer (void);
+bool urj_jam_constant_is_ok (const char *string);
+bool urj_jam_binary_constant_is_ok (const char *string);
+bool urj_jam_hex_constant_is_ok (const char *string);
+int32_t urj_jam_atol_bin (char *string);
+int32_t urj_jam_atol_hex (char *string);
+int urj_jam_constant_value (char *string, int32_t *value);
+void urj_jam_yyerror (char *msg);
+int urj_jam_yylex (void);
+int urj_jam_evaluate_expression (char *expression, int32_t *result,
+                             JAME_EXPRESSION_TYPE *result_type);
+int urj_jam_yyparse (void);
+
+#define GET_FIRST_CH jam_get_first_ch()
+#define GET_NEXT_CH jam_get_next_ch()
+#define UNGET_CH jam_unget_ch()
+#define CH jam_get_ch()
+}
+
+// Bison declarations
+%language "C"
+//always in current dir: %header "jamytab.h"
+//fixed jamexp.h parallel to jamexp.c: %header
+// ==> use --defines=$PATH_TO/jamytab.h
+%define api.prefix {urj_jam_yy}
+%define api.value.type {EXPN_STACK}
+%start stapl_expr
+
+%token AND_TOK         "&&"  // alias "AND"
+%token OR_TOK          "||"  // alias "OR"
+%token EQUALITY_TOK    "=="
+%token INEQUALITY_TOK  "!="
+// single-char cannot be %token 
+//%token GREATER_TOK   '>'
+//%token LESS_TOK      '<'
+%token GREATER_EQ_TOK  ">="
+%token LESS_OR_EQ_TOK  "<="
+%token LEFT_SHIFT_TOK  "<<"
+%token RIGHT_SHIFT_TOK ">>"
+%token DOT_DOT_TOK     ".."
+%token ABS_TOK         "ABS"
+%token INT_TOK         "INT"
+%token LOG2_TOK        "LOG2"
+%token SQRT_TOK        "SQRT"
+%token CIEL_TOK        "CEIL"
+%token FLOOR_TOK       "FLOOR"
+%token VALUE_TOK       "VALUE"
+%token IDENTIFIER_TOK  "IDENTIFIER"
+%token ARRAY_TOK       "ARRAY"
+%token ERROR_TOK       "ERROR"
+%token UNARY_MINUS     "UNARY_MINUS"
+%token UNARY_PLUS      "UNARY_PLUS"
+
+%code {
+static inline void jam_get_next_ch(void)
+{
+    urj_jam_ch = urj_jam_parse_string[urj_jam_strptr++];
+    urj_jam_token_buffer [urj_jam_token_buffer_index++] = urj_jam_ch;
+    if (urj_jam_token_buffer_index >= MAX_BUFFER_LENGTH)
+    {
+        --urj_jam_token_buffer_index;
+        --urj_jam_strptr;
+    }
+    urj_jam_token_buffer [urj_jam_token_buffer_index] = '\0';
+}
+
+static inline void jam_get_first_ch(void)
+{
+    urj_jam_token_buffer_index = 0;
+    jam_get_next_ch();
+}
+
+static inline void jam_unget_ch(void)
+{
+    urj_jam_strptr--;
+    urj_jam_token_buffer[--urj_jam_token_buffer_index] = '\0';
+}
+
+static inline char jam_get_ch(void)
+{
+    return urj_jam_ch;
+}
+
+/*
+*   Used by INT() function to convert Boolean array data to integer.  "msb"
+*   is the index of the most significant bit of the array, and "lsb" is the
+*   index of the least significant bit.  Typically msb > lsb, otherwise the
+*   bit order will be reversed when converted into integer format.
+*/
+int32_t
+urj_jam_convert_bool_to_int (int32_t *data, int32_t msb, int32_t lsb)
+{
+    int32_t i, increment = (msb > lsb) ? 1 : -1;
+    int32_t mask = 1L, result = 0L;
+
+    msb += increment;
+    for (i = lsb; i != msb; i += increment)
+    {
+        if (data[i >> 5] & (1L << (i & 0x1f)))
+            result |= mask;
+        mask <<= 1;
+    }
+
+    return result;
+}
+
+
+/************************************************************************/
+/*                                                                      */
+
+YYSTYPE
+urj_jam_exp_eval (OPERATOR_TYPE otype, YYSTYPE op1, YYSTYPE op2)
+/*  Evaluate op1 OTYPE op2.  op1, op2 are operands, OTYPE is operator   */
+/*                                                                      */
+/*  Some sneaky things are done to implement CEIL and FLOOR.            */
+/*                                                                      */
+/*  We do CEIL of LOG2 by default, and FLOOR of a DIVIDE by default.    */
+/*  Since we are lazy and we don't want to generate a parse tree,       */
+/*  we use the parser's reduce actions to tell us when to perform       */
+/*  an evaluation. But when CEIL and FLOOR are reduced, we know         */
+/*  nothing about the expression tree beneath it (it's been reduced!)   */
+/*                                                                      */
+/*  We keep this information around so we can calculate the CEIL or     */
+/*  FLOOR. We save value of the operand(s) or a divide in loper and     */
+/*  roper, then when CEIL/FLOOR get reduced, we just look at their      */
+/*  values.                                                             */
+/*                                                                      */
+{
+    YYSTYPE rtn;
+    int32_t tmp_val;
+    JAMS_SYMBOL_RECORD *symbol_rec;
+    JAMS_HEAP_RECORD *heap_rec;
+
+    rtn.child_otype = 0;
+    rtn.type = JAM_ILLEGAL_EXPR_TYPE;
+    rtn.val = 0;
+    rtn.loper = 0;
+    rtn.roper = 0;
+
+    switch (otype)
+    {
+    case UMINUS:
+        if ((op1.type == JAM_INTEGER_EXPR)
+            || (op1.type == JAM_INT_OR_BOOL_EXPR))
+        {
+            rtn.val = -1 * op1.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case ADD:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val + op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+
+            /* check for overflow */
+            if (((op1.val > 0) && (op2.val > 0) && (rtn.val < 0)) ||
+                ((op1.val < 0) && (op2.val < 0) && (rtn.val > 0)))
+            {
+                urj_jam_return_code = JAMC_INTEGER_OVERFLOW;
+            }
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case SUB:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val - op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+
+            /* check for overflow */
+            if (((op1.val > 0) && (op2.val < 0) && (rtn.val < 0)) ||
+                ((op1.val < 0) && (op2.val > 0) && (rtn.val > 0)))
+            {
+                urj_jam_return_code = JAMC_INTEGER_OVERFLOW;
+            }
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case MULT:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val * op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+
+            /* check for overflow */
+            if ((op1.val != 0) && (op2.val != 0) &&
+                (((rtn.val / op1.val) != op2.val) ||
+                 ((rtn.val / op2.val) != op1.val)))
+            {
+                urj_jam_return_code = JAMC_INTEGER_OVERFLOW;
+            }
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case DIV:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            if (op2.val != 0)
+            {
+                rtn.val = op1.val / op2.val;
+                rtn.loper = op1.val;
+                rtn.roper = op2.val;
+                rtn.child_otype = DIV;  /* Save info needed by CEIL */
+                rtn.type = JAM_INTEGER_EXPR;
+            }
+            else
+            {
+                urj_jam_return_code = JAMC_DIVIDE_BY_ZERO;
+            }
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case MOD:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val % op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case NOT:
+        if ((op1.type == JAM_BOOLEAN_EXPR)
+            || (op1.type == JAM_INT_OR_BOOL_EXPR))
+        {
+            rtn.val = (op1.val == 0) ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case AND:
+        if (((op1.type == JAM_BOOLEAN_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_BOOLEAN_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = (op1.val && op2.val) ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case OR:
+        if (((op1.type == JAM_BOOLEAN_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_BOOLEAN_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = (op1.val || op2.val) ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case BITWISE_NOT:
+        if ((op1.type == JAM_INTEGER_EXPR)
+            || (op1.type == JAM_INT_OR_BOOL_EXPR))
+        {
+            rtn.val = ~(uint32_t) op1.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case BITWISE_AND:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val & op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case BITWISE_OR:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val | op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case BITWISE_XOR:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val ^ op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case LEFT_SHIFT:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val << op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case RIGHT_SHIFT:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = op1.val >> op2.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case EQUALITY:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = (op1.val == op2.val) ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else if (((op1.type == JAM_BOOLEAN_EXPR)
+                  || (op1.type == JAM_INT_OR_BOOL_EXPR))
+                 && ((op2.type == JAM_BOOLEAN_EXPR)
+                     || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = ((op1.val && op2.val) || ((!op1.val) && (!op2.val)))
+                ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case INEQUALITY:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = (op1.val == op2.val) ? 0 : 1;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else if (((op1.type == JAM_BOOLEAN_EXPR)
+                  || (op1.type == JAM_INT_OR_BOOL_EXPR))
+                 && ((op2.type == JAM_BOOLEAN_EXPR)
+                     || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = ((op1.val && op2.val) || ((!op1.val) && (!op2.val)))
+                ? 0 : 1;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case GREATER_THAN:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = (op1.val > op2.val) ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case LESS_THAN:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = (op1.val < op2.val) ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case GREATER_OR_EQUAL:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = (op1.val >= op2.val) ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case LESS_OR_EQUAL:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            rtn.val = (op1.val <= op2.val) ? 1 : 0;
+            rtn.type = JAM_BOOLEAN_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case ABS:
+        if ((op1.type == JAM_INTEGER_EXPR) ||
+            (op1.type == JAM_INT_OR_BOOL_EXPR))
+        {
+            rtn.val = (op1.val < 0) ? (0 - op1.val) : op1.val;
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case INT:
+        rtn.val = op1.val;
+        rtn.type = JAM_INTEGER_EXPR;
+        break;
+
+    case LOG2:
+        if ((op1.type == JAM_INTEGER_EXPR) ||
+            (op1.type == JAM_INT_OR_BOOL_EXPR))
+        {
+            if (op1.val > 0)
+            {
+                rtn.child_otype = LOG2;
+                rtn.type = JAM_INTEGER_EXPR;
+                rtn.loper = op1.val;
+                tmp_val = op1.val;
+                rtn.val = 0;
+
+                while (tmp_val != 1)    /* ret_val = log2(left_val) */
+                {
+                    tmp_val = tmp_val >> 1;
+                    ++rtn.val;
+                }
+
+                /* if 2^(return_val) isn't the left_val, then the log */
+                /* wasn't a perfect integer, so we increment it */
+                if (pow (2, rtn.val) != op1.val)
+                {
+                    ++rtn.val;  /* Assume ceil of log2 */
+                }
+            }
+            else
+            {
+                urj_jam_return_code = JAMC_INTEGER_OVERFLOW;
+            }
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case SQRT:
+        if ((op1.type == JAM_INTEGER_EXPR) ||
+            (op1.type == JAM_INT_OR_BOOL_EXPR))
+        {
+            if (op1.val >= 0)
+            {
+                rtn.child_otype = SQRT;
+                rtn.type = JAM_INTEGER_EXPR;
+                rtn.loper = op1.val;
+                rtn.val = sqrt (op1.val);
+            }
+            else
+            {
+                urj_jam_return_code = JAMC_INTEGER_OVERFLOW;
+            }
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case CIEL:
+        if ((op1.type == JAM_INTEGER_EXPR)
+            || (op1.type == JAM_INT_OR_BOOL_EXPR))
+        {
+            if (op1.child_otype == DIV)
+            {
+                /* Below is true if wasn't perfect divide */
+                if ((op1.loper * op1.roper) != op1.val)
+                {
+                    rtn.val = op1.val + 1;      /* add 1 to get CEIL */
+                }
+                else
+                {
+                    rtn.val = op1.val;
+                }
+            }
+            else if (op1.child_otype == SQRT)
+            {
+                /* Below is true if wasn't perfect square-root */
+                if ((op1.val * op1.val) < op1.loper)
+                {
+                    rtn.val = op1.val + 1;      /* add 1 to get CEIL */
+                }
+                else
+                {
+                    rtn.val = op1.val;
+                }
+            }
+            else
+            {
+                rtn.val = op1.val;
+            }
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case FLOOR:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            if (op1.child_otype == LOG2)
+            {
+                if (pow (2, op1.val) != op1.loper)
+                {
+                    rtn.val = op1.val - 1;
+                }
+                else
+                {
+                    rtn.val = op1.val;
+                }
+            }
+            else
+            {
+                rtn.val = op1.val;
+            }
+            rtn.type = JAM_INTEGER_EXPR;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case ARRAY:
+        if ((op1.type == JAM_ARRAY_REFERENCE) &&
+            ((op2.type == JAM_INTEGER_EXPR)
+             || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            symbol_rec = (JAMS_SYMBOL_RECORD *) op1.val;
+            urj_jam_return_code =
+                urj_jam_get_array_value (symbol_rec, op2.val, &rtn.val);
+
+            if (urj_jam_return_code == JAMC_SUCCESS)
+            {
+                switch (symbol_rec->type)
+                {
+                case JAM_INTEGER_ARRAY_WRITABLE:
+                case JAM_INTEGER_ARRAY_INITIALIZED:
+                    rtn.type = JAM_INTEGER_EXPR;
+                    break;
+
+                case JAM_BOOLEAN_ARRAY_WRITABLE:
+                case JAM_BOOLEAN_ARRAY_INITIALIZED:
+                    rtn.type = JAM_BOOLEAN_EXPR;
+                    break;
+
+                default:
+                    urj_jam_return_code = JAMC_INTERNAL_ERROR;
+                    break;
+                }
+            }
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case POUND:
+        rtn.val = op1.val;
+        rtn.type = JAM_INTEGER_EXPR;
+        break;
+
+    case DOLLAR:
+        rtn.val = op1.val;
+        rtn.type = JAM_INTEGER_EXPR;
+        break;
+
+    case ARRAY_RANGE:
+        if (((op1.type == JAM_INTEGER_EXPR)
+             || (op1.type == JAM_INT_OR_BOOL_EXPR))
+            && ((op2.type == JAM_INTEGER_EXPR)
+                || (op2.type == JAM_INT_OR_BOOL_EXPR)))
+        {
+            symbol_rec = urj_jam_array_symbol_rec;
+
+            if ((symbol_rec != NULL) &&
+                ((symbol_rec->type == JAM_BOOLEAN_ARRAY_WRITABLE) ||
+                 (symbol_rec->type == JAM_BOOLEAN_ARRAY_INITIALIZED)))
+            {
+                heap_rec = (JAMS_HEAP_RECORD *) symbol_rec->value;
+
+                if (heap_rec != NULL)
+                {
+                    rtn.val = urj_jam_convert_bool_to_int (heap_rec->data,
+                                                       op1.val, op2.val);
+                }
+                rtn.type = JAM_INTEGER_EXPR;
+            }
+            else
+                urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    case ARRAY_ALL:
+        if (op1.type == JAM_ARRAY_REFERENCE)
+        {
+            symbol_rec = (JAMS_SYMBOL_RECORD *) op1.val;
+
+            if ((symbol_rec != NULL) &&
+                ((symbol_rec->type == JAM_BOOLEAN_ARRAY_WRITABLE) ||
+                 (symbol_rec->type == JAM_BOOLEAN_ARRAY_INITIALIZED)))
+            {
+                heap_rec = (JAMS_HEAP_RECORD *) symbol_rec->value;
+
+                if (heap_rec != NULL)
+                {
+                    rtn.val = urj_jam_convert_bool_to_int (heap_rec->data,
+                                                       heap_rec->dimension -
+                                                       1, 0);
+                }
+                rtn.type = JAM_INTEGER_EXPR;
+            }
+            else
+                urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        }
+        else
+            urj_jam_return_code = JAMC_TYPE_MISMATCH;
+        break;
+
+    default:
+        urj_jam_return_code = JAMC_INTERNAL_ERROR;
+        break;
+    }
+
+    return rtn;
+}
+
+
+/****************************************************************************/
+/*                                                                          */
+
+void
+urj_jam_exp_lexer (void)
+/*                                                                          */
+/*  Description:    Lexical analyzer for expressions.                       */
+/*                                                                          */
+/*                  Results are returned in the global variables            */
+/*                  urj_jam_token and urj_jam_token_buffer.                 */
+/*                                                                          */
+/*  References:     Compilers: Principles, Techniques and Tools by ASU      */
+/*                  (the Green Dragon book), section 3.4, Recognition of    */
+/*                  tokens.                                                 */
+/*                                                                          */
+/*  Returns:        Nothing                                                 */
+/*                                                                          */
+/****************************************************************************/
+{
+    BEGIN_MACHINE;
+
+  start:
+    GET_FIRST_CH;
+    if (CH == '\0')
+        ACCEPT (END_OF_STRING)  /* Fake an EOF! */
+    else if (CH == ' ' || iscntrl (CH))
+        goto start;             /* white space */
+    else if (isalpha (CH))
+        goto identifier;
+    else if (isdigit (CH))
+        goto number;
+    else if (CH == '&')
+    {
+        GET_NEXT_CH;
+        if (CH == '&')
+            ACCEPT (AND_TOK)
+        else
+        {
+            UNGET_CH;
+            ACCEPT ('&')
+        }
+    }
+    else if (CH == '|')
+    {
+        GET_NEXT_CH;
+        if (CH == '|')
+            ACCEPT (OR_TOK)
+        else
+        {
+            UNGET_CH;
+            ACCEPT ('|')
+        }
+    }
+    else if (CH == '=')
+    {
+        GET_NEXT_CH;
+        if (CH == '=')
+            ACCEPT (EQUALITY_TOK)
+        else
+        {
+            UNGET_CH;
+            ACCEPT ('=')
+        }
+    }
+    else if (CH == '!')
+    {
+        GET_NEXT_CH;
+        if (CH == '=')
+            ACCEPT (INEQUALITY_TOK)
+        else
+        {
+            UNGET_CH;
+            ACCEPT ('!')
+        }
+    }
+    else if (CH == '>')
+    {
+        GET_NEXT_CH;
+        if (CH == '=')
+            ACCEPT (GREATER_EQ_TOK)
+            else
+        if (CH == '>')
+            ACCEPT (RIGHT_SHIFT_TOK)
+        else
+        {
+            UNGET_CH;
+            ACCEPT (GREATER_TOK)
+        }
+    }
+    else if (CH == '<')
+    {
+        GET_NEXT_CH;
+        if (CH == '=')
+            ACCEPT (LESS_OR_EQ_TOK)
+            else
+        if (CH == '<')
+            ACCEPT (LEFT_SHIFT_TOK)
+        else
+        {
+            UNGET_CH;
+            ACCEPT (LESS_TOK)
+        }
+    }
+    else if (CH == '.')
+    {
+        GET_NEXT_CH;
+        if (CH == '.')
+            ACCEPT (DOT_DOT_TOK)
+        else
+        {
+            UNGET_CH;
+            ACCEPT ('.')
+        }
+    }
+    else
+        ACCEPT (CH)             /* single-chararcter token */
+      number:
+        GET_NEXT_CH;
+    if (isdigit (CH))
+        goto number;
+    else if (isalpha (CH) || CH == '_')
+        goto identifier;
+    else
+    {
+        UNGET_CH;
+        ACCEPT (VALUE_TOK)
+    }
+
+  identifier:
+    GET_NEXT_CH;
+    if (jam_is_name_char(CH))
+        goto identifier;
+    else
+    {
+        UNGET_CH;
+        ACCEPT (IDENTIFIER_TOK)
+    }
+
+    END_MACHINE;
+}
+
+
+/************************************************************************/
+/*                                                                      */
+
+bool
+urj_jam_constant_is_ok (const char *string)
+/*  This routine returns true if the value represented by string is     */
+/*  a valid signed decimal number.                                      */
+/*                                                                      */
+{
+    size_t ret = strspn (string, "-0123456789");
+    return string[ret] == '\0' ? true : false;
+}
+
+
+/************************************************************************/
+/*                                                                      */
+
+bool
+urj_jam_binary_constant_is_ok (const char *string)
+/*  This routine returns true if the value represented by string is     */
+/*  a valid binary number (containing only '0' and '1' characters).     */
+/*                                                                      */
+{
+    size_t ret = strspn (string, "10");
+    return string[ret] == '\0' ? true : false;
+}
+
+
+/************************************************************************/
+/*                                                                      */
+
+bool
+urj_jam_hex_constant_is_ok (const char *string)
+/*  This routine returns true if the value represented by string is     */
+/*  a valid hexadecimal number.                                         */
+/*                                                                      */
+{
+    size_t ret = strspn (string, "0123456789ABCDEFabcdef");
+    return string[ret] == '\0' ? true : false;
+}
+
+int32_t
+urj_jam_atol_bin (char *string)
+{
+    int32_t result = 0L;
+    int index = 0;
+
+    while ((string[index] == '0') || (string[index] == '1'))
+    {
+        result = (result << 1) + (string[index] - '0');
+        ++index;
+    }
+
+    return result;
+}
+
+int32_t
+urj_jam_atol_hex (char *string)
+{
+    int32_t result = 0L;
+
+    sscanf (string, "%x", &result);
+
+    return result;
+}
+
+
+/************************************************************************/
+/*                                                                      */
+
+int
+urj_jam_constant_value (char *string, int32_t *value)
+/*                                                                      */
+/*      This routine converts a string constant into its binary         */
+/*      value.                                                          */
+/*                                                                      */
+/*      Returns true for success, false if the string could not be      */
+/*      converted.                                                      */
+/*                                                                      */
+{
+    int status = false;
+
+    if (urj_jam_expression_type == '#')
+    {
+        if (urj_jam_binary_constant_is_ok (string))
+        {
+            *value = urj_jam_atol_bin (string);
+            urj_jam_expression_type = 0;
+            status = true;
+        }
+    }
+    else if (urj_jam_expression_type == '$')
+    {
+        if (urj_jam_hex_constant_is_ok (string))
+        {
+            *value = urj_jam_atol_hex (string);
+            urj_jam_expression_type = 0;
+            status = true;
+        }
+    }
+    else if (urj_jam_constant_is_ok (string))
+    {
+        if (string[0] == '-')
+        {
+            *value = 0 - atol (&string[1]);
+        }
+        else
+        {
+            *value = atol (string);
+        }
+        status = true;
+    }
+
+    return status;
+}
+
+
+/************************************************************************/
+/*                                                                      */
+
+void
+urj_jam_yyerror (char *msg)
+/*                                                                      */
+/*  WARNING: When compiling for YACC 5.0 using err_skel.c,              */
+/*           this function needs to be modified to be:                  */
+/*                                                                      */
+/*           urj_jam_yyerror(char *ms1, char *msg2)                     */
+/*                                                                      */
+/*  urj_jam_yyerror() handles syntax error messages from the parser.    */
+/*  Since we don't care about anything else but reporting the error,    */
+/*  just flag the error in urj_jam_return_code.                         */
+/*                                                                      */
+{
+    msg = msg;                  /* Avoid compiler warning about msg unused */
+
+    if (urj_jam_return_code == JAMC_SUCCESS)
+        urj_jam_return_code = JAMC_SYNTAX_ERROR;
+}
+
+
+/************************************************************************/
+/*                                                                      */
+
+int
+urj_jam_yylex (void)
+/*                                                                      */
+/*  This is the lexer function called by urj_jam_yyparse(). It calls           
 */
+/*  urj_jam_exp_lexer() to run as the DFA to return a token in urj_jam_token   
 */
+/*                                                                      */
+{
+    JAMS_SYMBOL_RECORD *symbol_rec = NULL;
+    int32_t val = 0L;
+    JAME_EXPRESSION_TYPE type = JAM_ILLEGAL_EXPR_TYPE;
+    int token_length;
+    int i;
+
+    urj_jam_exp_lexer ();
+
+    token_length = strlen (urj_jam_token_buffer);
+
+    if (token_length > 1)
+    {
+        for (i = 0; i < ARRAY_SIZE(jam_keyword_table); i++)
+        {
+            if (token_length == jam_keyword_table[i].length)
+            {
+                if (!strcmp
+                    (urj_jam_token_buffer, jam_keyword_table[i].string))
+                {
+                    urj_jam_token = jam_keyword_table[i].token;
+                }
+            }
+        }
+    }
+
+    if (urj_jam_token == VALUE_TOK)
+    {
+        if (urj_jam_constant_value (urj_jam_token_buffer, &val))
+        {
+            /* literal 0 and 1 may be interpreted as Integer or Boolean */
+            if ((val == 0) || (val == 1))
+            {
+                type = JAM_INT_OR_BOOL_EXPR;
+            }
+            else
+            {
+                type = JAM_INTEGER_EXPR;
+            }
+        }
+        else
+        {
+            urj_jam_return_code = JAMC_SYNTAX_ERROR;
+        }
+    }
+    else if (urj_jam_token == IDENTIFIER_TOK)
+    {
+        urj_jam_return_code =
+            urj_jam_get_symbol_record (urj_jam_token_buffer, &symbol_rec);
+
+        if (urj_jam_return_code == JAMC_SUCCESS)
+        {
+            switch (symbol_rec->type)
+            {
+            case JAM_INTEGER_SYMBOL:
+                /* Success, swap token to be a VALUE */
+                urj_jam_token = VALUE_TOK;
+                val = symbol_rec->value;
+                type = JAM_INTEGER_EXPR;
+                break;
+
+            case JAM_BOOLEAN_SYMBOL:
+                /* Success, swap token to be a VALUE */
+                urj_jam_token = VALUE_TOK;
+                val = symbol_rec->value ? 1 : 0;
+                type = JAM_BOOLEAN_EXPR;
+                break;
+
+            case JAM_INTEGER_ARRAY_WRITABLE:
+            case JAM_BOOLEAN_ARRAY_WRITABLE:
+            case JAM_INTEGER_ARRAY_INITIALIZED:
+            case JAM_BOOLEAN_ARRAY_INITIALIZED:
+                /* Success, swap token to be an ARRAY_TOK, */
+                /* save pointer to symbol record in value field */
+                urj_jam_token = ARRAY_TOK;
+                val = (int32_t) symbol_rec;
+                type = JAM_ARRAY_REFERENCE;
+                urj_jam_array_symbol_rec = symbol_rec;
+                break;
+
+            default:
+                urj_jam_return_code = JAMC_SYNTAX_ERROR;
+                break;
+            }
+        }
+    }
+    else if (urj_jam_token == '#')
+    {
+        urj_jam_expression_type = '#';
+    }
+    else if (urj_jam_token == '$')
+    {
+        urj_jam_expression_type = '$';
+    }
+
+    urj_jam_yylval.val = val;
+    urj_jam_yylval.type = type;
+    urj_jam_yylval.child_otype = 0;
+    urj_jam_yylval.loper = 0;
+    urj_jam_yylval.roper = 0;
+
+    return urj_jam_token;
+}
+
+
+/************************************************************************/
+/*                                                                      */
+
+JAM_RETURN_TYPE urj_jam_evaluate_expression
+    (char *expression, int32_t *result, JAME_EXPRESSION_TYPE *result_type)
+/*                                                                      */
+/*  THIS IS THE ENTRY POINT INTO THE EXPRESSION EVALUATOR.              */
+/*                                                                      */
+/*  s = a string representing the expression to be evaluated.           */
+/*      (e.g. "2+2+PARAMETER")                                          */
+/*                                                                      */
+/*  status = for returning true if evaluation was successful.           */
+/*           false if not.                                              */
+/*                                                                      */
+/*  This routine sets up the global variables and then calls            */
+/*  urj_jam_yyparse() to do the parsing. The reduce actions of the      */
+/*  parser evaluate the expression.                                     */
+/*                                                                      */
+/*  RETURNS: Value of the expression if success. 0 if FAIL.             */
+/*                                                                      */
+/*  Note: One should not rely on the return val to det.  success/fail   */
+/*        since it is possible for, say, "2-2" to be success and        */
+/*        return 0.                                                     */
+/*                                                                      */
+{
+    strcpy (urj_jam_parse_string, expression);
+    urj_jam_strptr = 0;
+    urj_jam_token_buffer_index = 0;
+    urj_jam_return_code = JAMC_SUCCESS;
+
+    urj_jam_yyparse ();
+
+    if (urj_jam_return_code == JAMC_SUCCESS)
+    {
+        if (result != 0)
+            *result = urj_jam_parse_value;
+        if (result_type != 0)
+            *result_type = urj_jam_expr_type;
+    }
+
+    return urj_jam_return_code;
+}
+}
+
+%% // Grammar rules
+
+// grammar start symbol
+stapl_expr: /*P1*/ logical_or_expr {
+   urj_jam_parse_value = $1.val;
+   urj_jam_expr_type = $1.type;
+}
+;
+pound_expr: /*P2*/ '#' "VALUE"[right] {
+   $$ = CALC (POUND, $right, NULL_EXP);
+}
+;
+dollar_expr: /*P3*/ '$' "VALUE"[right] {
+   $$ = CALC (DOLLAR, $right, NULL_EXP);
+}
+| '$' array_expr[right] {
+   $$ = CALC (DOLLAR, $right, NULL_EXP);
+}
+;
+array_range: /*P4*/ "ARRAY" '[' logical_or_expr[left] ".." 
logical_or_expr[right] ']' {
+   // ??: ARRAY seems to have been cached somewhere
+   $$ = CALC (ARRAY_RANGE, $left, $right);
+}
+;
+array_all: /*P5*/ "ARRAY"[left] '[' ']' {
+   $$ = CALC (ARRAY_ALL, $left, NULL_EXP);
+}
+;
+primary_expr: /*P6*/ "VALUE"
+| /*P7*/ '(' logical_or_expr[mid] ')' {
+   $$ = $mid;
+}
+| array_expr
+| abs_expr
+| ceil_expr
+| floor_expr
+| int_expr
+| log2_expr
+| sqrt_expr
+;
+unary_expr: primary_expr
+| /*P8*/ '+' unary_expr[right] {
+   $$ = $right;
+}
+| /*P9*/ '-' unary_expr[right] {
+   $$ = CALC (UMINUS, $right, NULL_EXP);
+}
+| /*P10*/ '!' unary_expr[right] {
+   $$ = CALC (NOT, $right, NULL_EXP);
+}
+| /*P11*/ '~' unary_expr[right] {
+   $$ = CALC (BITWISE_NOT, $right, NULL_EXP);
+}
+;
+additive_expr: multiplicative_expr
+| /*P12*/ additive_expr[left] '+' multiplicative_expr[right] {
+   $$ = CALC (ADD, $left, $right);
+}
+| /*P13*/ additive_expr[left] '-' multiplicative_expr[right] {
+   $$ = CALC (SUB, $left, $right);
+}
+;
+multiplicative_expr: unary_expr
+| /*P14*/ multiplicative_expr[left] '*' unary_expr[right] {
+   $$ = CALC (MULT, $left, $right);
+}
+| /*P15*/ multiplicative_expr[left] '/' unary_expr[right] {
+   $$ = CALC (DIV, $left, $right);
+}
+| /*P16*/ multiplicative_expr[left] '%' unary_expr[right] {
+   $$ = CALC (MOD, $left, $right);
+}
+;
+bitand_expr: equality_expr
+| /*P17*/ bitand_expr[left] '&' equality_expr[right] {
+   $$ = CALC (BITWISE_AND, $left, $right);
+}
+;
+bitor_expr: bitxor_expr
+| /*P18*/ bitor_expr[left] '|' bitxor_expr[right] {
+   $$ = CALC (BITWISE_OR, $left, $right);
+}
+;
+bitxor_expr: bitand_expr
+| /*P19*/ bitxor_expr[left] '^' bitand_expr[right] {
+   $$ = CALC (BITWISE_XOR, $left, $right);
+}
+;
+logical_and_expr: bitor_expr
+| /*P20*/ logical_and_expr[left] "&&" bitor_expr[right] {
+   $$ = CALC (AND, $left, $right);
+}
+;
+logical_or_expr: logical_and_expr
+| /*P21*/ logical_or_expr[left] "||" logical_and_expr[right] {
+   $$ = CALC (OR, $left, $right);
+}
+;
+shift_expr: additive_expr
+| /*P22*/ shift_expr[left] "<<" additive_expr[right] {
+   $$ = CALC (LEFT_SHIFT, $left, $right);
+}
+| /*P23*/ shift_expr[left] ">>" additive_expr[right] {
+   $$ = CALC (RIGHT_SHIFT, $left, $right);
+}
+;
+equality_expr: relational_expr
+| /*P24*/ equality_expr[left] "==" relational_expr[right] {
+   $$ = CALC (EQUALITY, $left, $right);
+}
+| /*P25*/ equality_expr[left] "!=" relational_expr[right] {
+   $$ = CALC (INEQUALITY, $left, $right);
+}
+;
+relational_expr: shift_expr
+| /*P26*/ relational_expr[left] '>' shift_expr[right] {
+   $$ = CALC (GREATER_THAN, $left, $right);
+}
+| /*P27*/ relational_expr[left] '<' shift_expr[right] {
+   $$ = CALC (LESS_THAN, $left, $right);
+}
+| /*28*/ relational_expr[left] ">=" shift_expr[right] {
+   $$ = CALC (GREATER_OR_EQUAL, $left, $right);
+}
+| /*P29*/ relational_expr[left] "<=" shift_expr[right] {
+   $$ = CALC (LESS_OR_EQUAL, $left, $right);
+}
+;
+abs_expr: /*P30*/ "ABS" '(' logical_or_expr[mid] ')' {
+   $$ = CALC (ABS, $mid, NULL_EXP);
+}
+;
+int_expr: /*P31*/ "INT" '(' pound_expr[mid] ')' {
+   $$ = CALC (INT, $mid, NULL_EXP);
+}
+| "INT" '(' dollar_expr[mid] ')' {
+   $$ = CALC (INT, $mid, NULL_EXP);
+}
+| "INT" '(' array_range[mid] ')' {
+   $$ = CALC (INT, $mid, NULL_EXP);
+}
+| "INT" '(' array_all[mid] ')' {
+   $$ = CALC (INT, $mid, NULL_EXP);
+}
+;
+log2_expr: /*P32*/ "LOG2" '(' logical_or_expr[mid] ')' {
+   $$ = CALC (LOG2, $mid, NULL_EXP);
+}
+;
+sqrt_expr: /*P33*/ "SQRT" '(' logical_or_expr[mid] ')' {
+   $$ = CALC (SQRT, $mid, NULL_EXP);
+}
+;
+ceil_expr: /*P34*/ "CEIL" '(' logical_or_expr[mid] ')' {
+   $$ = CALC (CIEL, $mid, NULL_EXP);
+}
+;
+floor_expr: /*P35*/ "FLOOR" '(' logical_or_expr[mid] ')' {
+   $$ = CALC (FLOOR, $mid, NULL_EXP);
+}
+;
+array_expr: /*P36*/ "ARRAY"[left] '[' logical_or_expr[right] ']' {
+   $$ = CALC (ARRAY, $left, $right);
+}
+;
diff --git a/urjtag/tests/stapl/jamexp_gen.c b/urjtag/tests/stapl/jamexp_gen.c
new file mode 100644
index 00000000..65d599c0
--- /dev/null
+++ b/urjtag/tests/stapl/jamexp_gen.c
@@ -0,0 +1,35 @@
+/**
+ * \author SPDX-FileCopyrightText: 2022 Peter Poeschl <pp+ujt2...@nest-ai.de>
+ *
+ * \copyright SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * \file jamexp_gen.c
+ * \brief Unit test program for jamexp.c generated by Bison from jamexp.y
+ *
+ * Test idea:
+ * * assume non-generated jamexp.c is correct
+ * * create tests for urj_jam_evaluate_expression() to exercise all productions
+ * * use the same test vectors to validate syntax in jamexp.c generated from
+ *   jamexp.y
+ */
+
+#include "jamexp_shrd.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jamdefs.h"
+#include "jamytab.h"
+
+#include "tap/basic.h"
+
+int main(void)
+{
+#if URJ_JAM_YYDEBUG
+   const char *const env_URJ_JAM_YYDEBUG = getenv("URJ_JAM_YYDEBUG");
+   urj_jam_yydebug
+      = env_URJ_JAM_YYDEBUG && !strcmp(env_URJ_JAM_YYDEBUG, "1");
+#endif
+   plan(PLAN_TESTS);
+
+   check__urj_jam_evaluate_expression();
+}
-- 
2.35.1






_______________________________________________
UrJTAG-development mailing list
UrJTAG-development@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/urjtag-development

Reply via email to