Cloned SEACAS for EXODUS library with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

587 lines
26 KiB

2 years ago
// Copyright(C) 1999-2023 National Technology & Engineering Solutions
// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
// NTESS, the U.S. Government retains certain rights in this software.
//
// See packages/seacas/LICENSE for details
%{
#include "aprepro.h"
#include "apr_util.h"
#include "apr_array.h"
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <cerrno>
#include <cstring>
#include <cstdio>
#include <cfenv>
namespace {
void reset_error()
{
#if !defined(WIN32) && !defined(__WIN32__) && !defined(_WIN32) && !defined(_MSC_VER) && \
!defined(__MINGW32__) && !defined(_WIN64) && !defined(__MINGW64__)
#ifndef math_errhandling
#define math_errhandling MATH_ERRNO
#endif
if (math_errhandling & MATH_ERREXCEPT) {
std::feclearexcept(FE_ALL_EXCEPT);
}
if (math_errhandling & MATH_ERRNO) {
errno = 0;
}
#endif
}
}
namespace SEAMS {
extern bool echo;
}
%}
%require "3.2"
/* add debug output code to generated parser. disable this for release
* versions. */
%debug
/* write out a header file containing the token defines */
%defines
/* use newer C++ skeleton file */
%skeleton "lalr1.cc"
/* namespace to enclose parser in */
%define api.prefix {SEAMS}
/* set the parser's class identifier */
%define api.parser.class {Parser}
%define parse.error verbose
/* aprepro is passed by reference to the parser and to the scanner. This
* provides a simple but effective pure interface, not relying on global
* variables. */
%parse-param { class Aprepro& aprepro }
%union {
double val; /* For returning numbers. */
struct symrec *tptr; /* For returning symbol-table pointers */
char *string; /* For returning quoted strings */
struct array *arrval; /* For returning arrays */
}
%token <val> NUM /* Simple double precision number */
%token <string> QSTRING /* Quoted string */
%token <tptr> UNDVAR /* Variable and function */
%token <tptr> VAR
%token <tptr> SVAR /* String Variable */
%token <tptr> IMMVAR /* Immutable Variable */
%token <tptr> IMMSVAR /* Immutable String Variable */
%token <tptr> AVAR /* array data [i,j] */
%token <tptr> FNCT
%token <tptr> SFNCT
%token <tptr> AFNCT
%type <val> exp
%type <arrval> aexp
%type <val> bool
%type <string> sexp
%token END 0 "end of file"
%token COMMA LPAR RPAR LBRACK RBRACK LBRACE RBRACE SEMI
/* Precedence (Lowest to Highest) and associativity */
%right EQUAL
%right EQ_PLUS EQ_MINUS
%right EQ_TIME EQ_DIV
%right EQ_POW
%right QUEST COLON
%left LOR /* Logical OR */
%left LAND /* Logical AND */
%left LT GT LE GE EQ NE /* <=, >=, ==, != */
%left PLU SUB
%left DIV TIM MOD
%left UNARY NOT /* Negation--unary minus/plus */
%right POW /* Exponentiation */
%left INC DEC /* increment (++), decrement (--) */
%left CONCAT /* Concatenate Strings */
%{
#include "aprepro.h"
#include "apr_scanner.h"
/* this "connects" the bison parser in aprepro to the flex scanner class
* object. it defines the yylex() function call to pull the next token from the
* current lexer object of the aprepro context. */
#undef yylex
#define yylex aprepro.lexer->lex
%}
/* Grammar Rules: */
%%
input: /* empty rule */
| input line
;
line: '\n' { if (echo) aprepro.lexer->LexerOutput("\n", 1); }
| LBRACE exp RBRACE { if (echo) {
static char tmpstr[512];
SEAMS::symrec *format = aprepro.getsym("_FORMAT");
int len = snprintf(tmpstr, 512, format->value.svar.c_str(), $2);
aprepro.lexer->LexerOutput(tmpstr, len);
}
}
| LBRACE sexp RBRACE { if (echo && $2 != NULL) {
aprepro.lexer->LexerOutput($2, strlen($2));
}
}
| LBRACE aexp RBRACE { }
| LBRACE RBRACE { }
| error RBRACE { yyerrok; }
;
bool: exp LT exp { $$ = $1 < $3; }
| exp GT exp { $$ = $1 > $3; }
| NOT exp { $$ = !($2); }
| exp LE exp { $$ = $1 <= $3; }
| exp GE exp { $$ = $1 >= $3; }
| exp EQ exp { $$ = $1 == $3; }
| exp NE exp { $$ = $1 != $3; }
| exp LOR exp { $$ = $1 || $3; }
| exp LAND exp { $$ = $1 && $3; }
| bool LOR bool { $$ = $1 || $3; }
| bool LAND bool { $$ = $1 && $3; }
| bool LOR exp { $$ = $1 || $3; }
| bool LAND exp { $$ = $1 && $3; }
| exp LOR bool { $$ = $1 || $3; }
| exp LAND bool { $$ = $1 && $3; }
| LPAR bool RPAR { $$ = $2; }
;
bool: sexp LT sexp { $$ = (strcmp($1,$3) < 0 ? 1 : 0); }
| sexp GT sexp { $$ = (strcmp($1,$3) > 0 ? 1 : 0); }
| sexp LE sexp { $$ = (strcmp($1,$3) <= 0 ? 1 : 0); }
| sexp GE sexp { $$ = (strcmp($1,$3) >= 0 ? 1 : 0); }
| sexp EQ sexp { $$ = (strcmp($1,$3) == 0 ? 1 : 0); }
| sexp NE sexp { $$ = (strcmp($1,$3) != 0 ? 1 : 0); }
aexp: AVAR { $$ = aprepro.make_array(*($1->value.avar)); }
| AFNCT LPAR sexp RPAR {
if (arg_check($1, $1->value.arrfnct_c == NULL))
$$ = (*($1->value.arrfnct_c))($3);
else
yyerrok;
}
| AFNCT LPAR sexp COMMA exp RPAR {
if (arg_check($1, $1->value.arrfnct_cd == NULL))
$$ = (*($1->value.arrfnct_cd))($3,$5);
else
yyerrok;
}
| AFNCT LPAR sexp COMMA sexp RPAR {
if (arg_check($1, $1->value.arrfnct_cc == NULL))
$$ = (*($1->value.arrfnct_cc))($3,$5);
else
yyerrok;
}
| AFNCT LPAR exp COMMA exp COMMA exp RPAR {
if (arg_check($1, $1->value.arrfnct_ddd == NULL))
$$ = (*($1->value.arrfnct_ddd))($3,$5,$7);
else
yyerrok;
}
| AFNCT LPAR exp COMMA exp RPAR {
if (arg_check($1, $1->value.arrfnct_dd == NULL))
$$ = (*($1->value.arrfnct_dd))($3,$5);
else
yyerrok;
}
| AFNCT LPAR exp RPAR {
if (arg_check($1, $1->value.arrfnct_d == NULL))
$$ = (*($1->value.arrfnct_d))($3);
else
yyerrok;
}
| AFNCT LPAR aexp RPAR {
if (arg_check($1, $1->value.arrfnct_a == NULL))
$$ = (*($1->value.arrfnct_a))($3);
else
yyerrok;
}
| SVAR EQUAL aexp { $$ = $3;
$1->value.avar = $3;
redefined_warning(aprepro, $1);
set_type(aprepro, $1, token::AVAR); }
| VAR EQUAL aexp { $$ = $3;
$1->value.avar= $3;
redefined_warning(aprepro, $1);
set_type(aprepro, $1, token::AVAR); }
| AVAR EQUAL aexp { $$ = $3; aprepro.redefine_array($1->value.avar); $1->value.avar = $3;
redefined_warning(aprepro, $1);
set_type(aprepro, $1, token::AVAR); }
| UNDVAR EQUAL aexp { $$ = $3; $1->value.avar = $3;
set_type(aprepro, $1, token::AVAR); }
| aexp PLU aexp { if ($1->cols == $3->cols && $1->rows == $3->rows ) {
$$ = array_add($1, $3);
}
else {
yyerror(aprepro, "Arrays do not have same row and column count");
yyerrok;
}
}
| SUB aexp %prec UNARY { $$ = array_scale($2, -1.0); }
| aexp SUB aexp { if ($1->cols == $3->cols && $1->rows == $3->rows ) {
$$ = array_sub($1, $3);
}
else {
yyerror(aprepro, "Arrays do not have same row and column count");
yyerrok;
}
}
| aexp TIM exp { $$ = array_scale($1, $3); }
| aexp DIV exp { $$ = array_scale($1, 1.0/$3); }
| exp TIM aexp { $$ = array_scale($3, $1); }
| aexp TIM aexp { if ($1->cols == $3->rows) {
$$ = array_mult($1, $3);
}
else {
yyerror(aprepro, "Column count of first array does not match row count of second array");
yyerrok;
}
}
sexp: QSTRING { $$ = $1; }
| SVAR { $$ = (char*)$1->value.svar.c_str(); }
| IMMSVAR { $$ = (char*)$1->value.svar.c_str(); }
| UNDVAR EQUAL sexp { $$ = $3; $1->value.svar = $3;
set_type(aprepro, $1, Parser::token::SVAR); }
| SVAR EQUAL sexp { $$ = $3;
$1->value.svar = $3;
redefined_warning(aprepro, $1); }
| VAR EQUAL sexp { $$ = $3;
$1->value.svar= $3;
redefined_warning(aprepro, $1);
set_type(aprepro, $1, token::SVAR); }
| AVAR EQUAL sexp { $$ = $3;
aprepro.redefine_array($1->value.avar);
$1->value.svar= $3;
redefined_warning(aprepro, $1);
set_type(aprepro, $1, token::SVAR); }
| IMMSVAR EQUAL sexp { $$ = (char*)$1->value.svar.c_str(); immutable_modify(aprepro, $1); }
| IMMVAR EQUAL sexp { immutable_modify(aprepro, $1); YYERROR; }
| SFNCT LPAR sexp RPAR {
if (arg_check($1, $1->value.strfnct_c == NULL))
$$ = (char*)(*($1->value.strfnct_c))($3);
else
$$ = (char*)"";
}
| SFNCT LPAR RPAR {
if (arg_check($1, $1->value.strfnct == NULL))
$$ = (char*)(*($1->value.strfnct))();
else
$$ = (char*)"";
}
| SFNCT LPAR exp RPAR {
if (arg_check($1, $1->value.strfnct_d == NULL))
$$ = (char*)(*($1->value.strfnct_d))($3);
else
$$ = (char*)"";
}
| SFNCT LPAR aexp RPAR {
if (arg_check($1, $1->value.strfnct_a == NULL))
$$ = (char*)(*($1->value.strfnct_a))($3);
else
$$ = (char*)"";
}
| sexp CONCAT sexp { concat_string($1, $3, &$$); }
| SFNCT LPAR exp COMMA exp RPAR {
if (arg_check($1, $1->value.strfnct_dd == NULL))
$$ = (char*)(*($1->value.strfnct_dd))($3, $5);
else
$$ = (char*)"";
}
| SFNCT LPAR exp COMMA sexp COMMA sexp COMMA sexp COMMA sexp RPAR {
if (arg_check($1, $1->value.strfnct_dcccc == NULL))
$$ = (char*)(*($1->value.strfnct_dcccc))($3, $5, $7, $9, $11);
else
$$ = (char*)"";
}
| SFNCT LPAR exp COMMA sexp COMMA sexp RPAR {
if (arg_check($1, $1->value.strfnct_dcc == NULL))
$$ = (char*)(*($1->value.strfnct_dcc))($3, $5, $7);
else
$$ = (char*)"";
}
| SFNCT LPAR sexp COMMA sexp COMMA sexp RPAR {
if (arg_check($1, $1->value.strfnct_ccc == NULL))
$$ = (char*)(*($1->value.strfnct_ccc))($3, $5, $7);
else
$$ = (char*)"";
}
| SFNCT LPAR sexp COMMA sexp RPAR {
if (arg_check($1, $1->value.strfnct_cc == NULL))
$$ = (char*)(*($1->value.strfnct_cc))($3, $5);
else
$$ = (char*)"";
}
| bool QUEST sexp COLON sexp { $$ = ($1) ? ($3) : ($5); }
exp: NUM { $$ = $1; }
| INC NUM { $$ = $2 + 1; }
| DEC NUM { $$ = $2 - 1; }
| VAR { $$ = $1->value.var; }
| IMMVAR { $$ = $1->value.var; }
| INC VAR { $$ = ++($2->value.var); }
| DEC VAR { $$ = --($2->value.var); }
| VAR INC { $$ = ($1->value.var)++; }
| VAR DEC { $$ = ($1->value.var)--; }
| VAR EQUAL exp { $$ = $3; $1->value.var = $3;
redefined_warning(aprepro, $1); }
| SVAR EQUAL exp { $$ = $3; $1->value.var = $3;
redefined_warning(aprepro, $1);
set_type(aprepro, $1, token::VAR); }
| AVAR EQUAL exp { $$ = $3;
aprepro.redefine_array($1->value.avar);
$1->value.var= $3;
redefined_warning(aprepro, $1);
set_type(aprepro, $1, token::VAR); }
| VAR EQ_PLUS exp { $1->value.var += $3; $$ = $1->value.var; }
| VAR EQ_MINUS exp { $1->value.var -= $3; $$ = $1->value.var; }
| VAR EQ_TIME exp { $1->value.var *= $3; $$ = $1->value.var; }
| VAR EQ_DIV exp { $1->value.var /= $3; $$ = $1->value.var; }
| VAR EQ_POW exp { reset_error();
$1->value.var = std::pow($1->value.var,$3);
$$ = $1->value.var;
SEAMS::math_error(aprepro, "Power");
}
| INC IMMVAR { $$ = $2->value.var; immutable_modify(aprepro, $2); }
| DEC IMMVAR { $$ = $2->value.var; immutable_modify(aprepro, $2); }
| IMMVAR INC { $$ = $1->value.var; immutable_modify(aprepro, $1); }
| IMMVAR DEC { $$ = $1->value.var; immutable_modify(aprepro, $1); }
| IMMVAR EQUAL exp { $$ = $1->value.var; immutable_modify(aprepro, $1); }
| IMMSVAR EQUAL exp { immutable_modify(aprepro, $1); YYERROR; }
| IMMVAR EQ_PLUS exp { $$ = $1->value.var; immutable_modify(aprepro, $1); }
| IMMVAR EQ_MINUS exp { $$ = $1->value.var; immutable_modify(aprepro, $1); }
| IMMVAR EQ_TIME exp { $$ = $1->value.var; immutable_modify(aprepro, $1); }
| IMMVAR EQ_DIV exp { $$ = $1->value.var; immutable_modify(aprepro, $1); }
| IMMVAR EQ_POW exp { $$ = $1->value.var; immutable_modify(aprepro, $1); }
| UNDVAR { $$ = $1->value.var;
undefined_error(aprepro, $1->name); }
| INC UNDVAR { $$ = ++($2->value.var);
set_type(aprepro, $2, token::VAR);
undefined_error(aprepro, $2->name); }
| DEC UNDVAR { $$ = --($2->value.var);
set_type(aprepro, $2, token::VAR);
undefined_error(aprepro, $2->name); }
| UNDVAR INC { $$ = ($1->value.var)++;
set_type(aprepro, $1, token::VAR);
undefined_error(aprepro, $1->name); }
| UNDVAR DEC { $$ = ($1->value.var)--;
set_type(aprepro, $1, token::VAR);
undefined_error(aprepro, $1->name); }
| UNDVAR EQUAL exp { $$ = $3; $1->value.var = $3;
set_type(aprepro, $1, token::VAR); }
| UNDVAR EQ_PLUS exp { $1->value.var += $3; $$ = $1->value.var;
set_type(aprepro, $1, token::VAR);
undefined_error(aprepro, $1->name); }
| UNDVAR EQ_MINUS exp { $1->value.var -= $3; $$ = $1->value.var;
set_type(aprepro, $1, token::VAR);
undefined_error(aprepro, $1->name); }
| UNDVAR EQ_TIME exp { $1->value.var *= $3; $$ = $1->value.var;
set_type(aprepro, $1, token::VAR);
undefined_error(aprepro, $1->name); }
| UNDVAR EQ_DIV exp { $1->value.var /= $3; $$ = $1->value.var;
set_type(aprepro, $1, token::VAR);
undefined_error(aprepro, $1->name); }
| UNDVAR EQ_POW exp { reset_error();
$1->value.var = std::pow($1->value.var,$3);
$$ = $1->value.var;
set_type(aprepro, $1, token::VAR);
SEAMS::math_error(aprepro, "Power");
undefined_error(aprepro, $1->name); }
| FNCT LPAR RPAR {
if (arg_check($1, $1->value.fnctptr == NULL))
$$ = (*($1->value.fnctptr))();
else
$$ = 0.0;
}
| FNCT LPAR exp RPAR {
if (arg_check($1, $1->value.fnctptr_d == NULL))
$$ = (*($1->value.fnctptr_d))($3);
else
$$ = 0.0;
}
| FNCT LPAR sexp RPAR {
if (arg_check($1, $1->value.fnctptr_c == NULL))
$$ = (*($1->value.fnctptr_c))($3);
else
$$ = 0.0;
}
| FNCT LPAR aexp RPAR {
if (arg_check($1, $1->value.fnctptr_a == NULL))
$$ = (*($1->value.fnctptr_a))($3);
else
$$ = 0.0;
}
| FNCT LPAR sexp COMMA exp RPAR {
if (arg_check($1, $1->value.fnctptr_cd == NULL))
$$ = (*($1->value.fnctptr_cd))($3, $5);
else
$$ = 0.0;
}
| FNCT LPAR exp COMMA sexp RPAR {
if (arg_check($1, $1->value.fnctptr_dc == NULL))
$$ = (*($1->value.fnctptr_dc))($3, $5);
else
$$ = 0.0;
}
| FNCT LPAR sexp COMMA sexp RPAR {
if (arg_check($1, $1->value.fnctptr_cc == NULL))
$$ = (*($1->value.fnctptr_cc))($3, $5);
else
$$ = 0.0;
}
| FNCT LPAR sexp COMMA sexp COMMA sexp RPAR {
if (arg_check($1, $1->value.fnctptr_ccc == NULL))
$$ = (*($1->value.fnctptr_ccc))($3,$5,$7);
else
yyerrok;
}
| FNCT LPAR exp COMMA exp RPAR {
if (arg_check($1, $1->value.fnctptr_dd == NULL))
$$ = (*($1->value.fnctptr_dd))($3, $5);
else
$$ = 0.0;
}
| FNCT LPAR exp COMMA exp COMMA exp RPAR {
if (arg_check($1, $1->value.fnctptr_ddd == NULL))
$$ = (*($1->value.fnctptr_ddd))($3, $5, $7);
else
$$ = 0.0;
}
| FNCT LPAR sexp COMMA sexp COMMA exp RPAR {
if (arg_check($1, $1->value.fnctptr_ccd == NULL))
$$ = (*($1->value.fnctptr_ccd))($3, $5, $7);
else
$$ = 0.0;
}
| FNCT LPAR exp COMMA exp SEMI exp COMMA exp RPAR {
if (arg_check($1, $1->value.fnctptr_dddd == NULL))
$$ = (*($1->value.fnctptr_dddd))($3, $5, $7, $9);
else
$$ = 0.0;
}
| FNCT LPAR exp COMMA exp COMMA exp COMMA exp RPAR {
if (arg_check($1, $1->value.fnctptr_dddd == NULL))
$$ = (*($1->value.fnctptr_dddd))($3, $5, $7, $9);
else
$$ = 0.0;
}
| FNCT LPAR exp COMMA exp COMMA exp COMMA exp COMMA sexp RPAR {
if (arg_check($1, $1->value.fnctptr_ddddc == NULL))
$$ = (*($1->value.fnctptr_ddddc))($3, $5, $7, $9, $11);
else
$$ = 0.0;
}
| FNCT LPAR exp COMMA exp COMMA exp COMMA exp COMMA exp COMMA exp RPAR {
if (arg_check($1, $1->value.fnctptr_dddddd == NULL))
$$ = (*($1->value.fnctptr_dddddd))($3, $5, $7, $9, $11, $13);
else
$$ = 0.0;
}
| exp PLU exp { $$ = $1 + $3; }
| exp SUB exp { $$ = $1 - $3; }
| exp TIM exp { $$ = $1 * $3; }
| exp DIV exp { if ($3 == 0.)
{
yyerror(aprepro, "Zero divisor");
yyerrok;
}
else
$$ = $1 / $3; }
| exp MOD exp { if ($3 == 0.)
{
yyerror(aprepro, "Zero divisor");
yyerrok;
}
else
$$ = (int)$1 % (int)$3; }
| SUB exp %prec UNARY { $$ = -$2; }
| PLU exp %prec UNARY { $$ = $2; }
| exp POW exp { reset_error();
$$ = std::pow($1, $3);
SEAMS::math_error(aprepro, "Power"); }
| LPAR exp RPAR { $$ = $2; }
| LBRACK exp RBRACK { reset_error();
$$ = (double)($2 < 0 ? -floor(-($2)): floor($2) );
SEAMS::math_error(aprepro, "floor (int)"); }
| bool { $$ = ($1) ? 1 : 0; }
| bool QUEST exp COLON exp { $$ = ($1) ? ($3) : ($5); }
| AVAR LBRACK exp RBRACK { $$ = array_value($1->value.avar, $3, 0); }
| AVAR LBRACK exp COMMA exp RBRACK { $$ = array_value($1->value.avar, $3, $5); }
| AVAR LBRACK exp RBRACK EQUAL exp
{ $$ = $6;
array *arr = $1->value.avar;
int cols = arr->cols;
if (cols > 1) {
yyerror(aprepro, "Cannot use [index] array access with multi-column array");
yyerrok;
}
int rows = arr->rows;
int row = $3;
if (aprepro.ap_options.one_based_index) {
row--;
}
if (row < rows) {
int offset = row*cols;
$1->value.avar->data[offset] = $6;
}
else {
yyerror(aprepro, "Row or Column index out of range");
yyerrok;
}
}
| AVAR LBRACK exp COMMA exp RBRACK EQUAL exp
{ $$ = $8;
array *arr = $1->value.avar;
int cols = arr->cols;
int rows = arr->rows;
int row = $3;
int col = $5;
if (aprepro.ap_options.one_based_index) {
row--;
col--;
}
if (row < rows && col < cols) {
int offset = row*cols+col;
$1->value.avar->data[offset] = $8;
}
else {
yyerror(aprepro, "Row or Column index out of range");
yyerrok;
}
}
/* End of grammar */
%%
void SEAMS::Parser::error(const std::string& m)
{
aprepro.error(m);
}