Skip to content
Snippets Groups Projects
config_process.y 56 KiB
Newer Older
/******************************************************************************
Elemer Lelik's avatar
Elemer Lelik committed
 * Copyright (c) 2000-2016 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
Elemer Lelik's avatar
Elemer Lelik committed
 *
 * Contributors:
 *   
 *   Baji, Laszlo
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Beres, Szabolcs
 *   Delic, Adam
 *   Forstner, Matyas
 *   Kovacs, Ferenc
 *   Pandi, Krisztian
 *   Raduly, Csaba
 *   Szabados, Kristof
 *   Szabo, Bence Janos
Elemer Lelik's avatar
Elemer Lelik committed
 *   Szabo, Janos Zoltan – initial implementation
 *   Szalai, Gabor
 *   Zalanyi, Balazs Andor
 *
 ******************************************************************************/
%{

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>

#include <openssl/bn.h>

#include "../common/config_preproc.h"

#include "Param_Types.hh"
#include "Integer.hh"
#include "Float.hh"
#include "Boolean.hh"
#include "Objid.hh"
#include "Verdicttype.hh"
#include "Bitstring.hh"
#include "Hexstring.hh"
#include "Octetstring.hh"
#include "Charstring.hh"
#include "Universal_charstring.hh"

#include "Module_list.hh"
#include "Port.hh"
#include "Runtime.hh"

#include "LoggingBits.hh"
#include "LoggingParam.hh"

Elemer Lelik's avatar
Elemer Lelik committed
#include "Profiler.hh"

#define YYERROR_VERBOSE

#include "config_process.lex.hh"

extern void reset_config_process_lex(const char* fname);
extern void config_process_close();
extern int config_process_get_current_line();
extern std::string get_cfg_process_current_file();

static int config_process_parse();
static void check_duplicate_option(const char *section_name,
    const char *option_name, boolean& option_flag);
static void check_ignored_section(const char *section_name);
static void set_param(Module_Param& module_param);
static unsigned char char_to_hexdigit(char c);

static boolean error_flag = FALSE;

static Module_Param* parsed_module_param = NULL;
static char * parsing_error_messages = NULL;

/*
For detecting duplicate entries in the config file. Start out as FALSE,
set to TRUE bycheck_duplicate_option().
Exception: duplication of parameters that can be component specific is checked
by set_xxx(), these start out as TRUE.
*/
static boolean file_name_set = FALSE,
	file_mask_set = TRUE,
	console_mask_set = TRUE,
	timestamp_format_set = FALSE,
	source_info_format_set = FALSE,
	append_file_set = FALSE,
	log_event_types_set = FALSE,
	log_entity_name_set = FALSE,
	begin_controlpart_command_set = FALSE,
	end_controlpart_command_set = FALSE,
	begin_testcase_command_set = FALSE,
	end_testcase_command_set = FALSE,
	log_file_size_set = TRUE,
	log_file_number_set = TRUE,
	log_disk_full_action_set = TRUE,
	matching_verbosity_set = FALSE,
	logger_plugins_set = FALSE,
	plugin_specific_set = FALSE;

int execute_list_len = 0;
execute_list_item *execute_list = NULL;

string_map_t *config_defines;

%}

%union{
	char 					*str_val;
	int_val_t				*int_val;
	int						int_native;
	unsigned int			uint_val;
	double					float_val;
	boolean					bool_val;
	param_objid_t			objid_val;
	verdicttype				verdict_val;
	param_bitstring_t		bitstring_val;
	param_hexstring_t		hexstring_val;
	param_charstring_t		charstring_val;
	param_octetstring_t		octetstring_val;
	universal_char			universal_char_val;
	param_universal_charstring_t universal_charstring_val;
	Module_Param::operation_type_t param_optype_val;
  Vector<Module_Param*>* module_param_list;
	Module_Param*			module_param_val;
  Module_Param_Length_Restriction* module_param_length_restriction;
	Vector<char*>*		name_vector;
	component_id_t		comp_id;
	execute_list_item	execute_item_val;
	TTCN_Logger::emergency_logging_behaviour_t emergency_logging_behaviour_value;
	TTCN_Logger::timestamp_format_t timestamp_value;
	TTCN_Logger::source_info_format_t source_info_value;
  TTCN_Logger::log_event_types_t log_event_types_value;
  TTCN_Logger::disk_full_action_t disk_full_action_value;
  TTCN_Logger::matching_verbosity_t matching_verbosity_value;
	TTCN_Logger::Severity	logseverity_val;
	Logging_Bits logoptions_val;

  logging_plugin_t *logging_plugins;
	logging_param_t logging_params;
	logging_setting_t logging_param_line;
  struct {
    size_t nElements;
    const char **elements;
  } uid_list;
}

%token ModuleParametersKeyword
%token LoggingKeyword
Elemer Lelik's avatar
Elemer Lelik committed
%token ProfilerKeyword
%token TestportParametersKeyword
%token ExecuteKeyword
%token ExternalCommandsKeyword
%token GroupsKeyword
%token ComponentsKeyword
%token MainControllerKeyword
%token IncludeKeyword
%token DefineKeyword

%token Detailed
%token Compact
%token ObjIdKeyword "objid"
%token CharKeyword "char"
%token ControlKeyword "control"
%token MTCKeyword "mtc"
%token SystemKeyword "system"
%token NULLKeyword "NULL"
%token nullKeyword "null"
%token OmitKeyword "omit"
%token ComplementKeyword "complement"
%token DotDot ".."
%token SupersetKeyword "superset"
%token SubsetKeyword "subset"
%token PatternKeyword "pattern"
%token PermutationKeyword "permutation"
%token LengthKeyword "length"
%token IfpresentKeyword "ifpresent"
%token InfinityKeyword "infinity"
%token AssignmentChar ":= or ="
%token ConcatChar "&="
%token LogFile "LogFile or FileName"
%token EmergencyLogging
%token EmergencyLoggingBehaviour
%token EmergencyLoggingMask
Elemer Lelik's avatar
Elemer Lelik committed
%token EmergencyLoggingForFailVerdict
%token BufferAll
%token BufferMasked
%token FileMask
%token ConsoleMask
%token TimestampFormat
%token ConsoleTimestampFormat
%token SourceInfoFormat "LogSourceInfo or SourceInfoFormat"
%token AppendFile
%token LogEventTypes
%token LogEntityName
%token BeginControlPart
%token EndControlPart
%token BeginTestCase
%token EndTestCase
%token <str_val> Identifier
%token <str_val> ASN1LowerIdentifier "ASN.1 identifier beginning with a lowercase letter"
Elemer Lelik's avatar
Elemer Lelik committed
%token <int_val> Number MPNumber "integer value"
%token <float_val> Float MPFloat "float value"
%token <bool_val> BooleanValue "true or false"
%token <verdict_val> VerdictValue
%token <bitstring_val> Bstring "bit string value"
%token <hexstring_val> Hstring "hex string value"
%token <octetstring_val> Ostring "octet string value"
%token <str_val> BstringMatch "bit string template"
%token <str_val> HstringMatch "hex string template"
%token <str_val> OstringMatch "octet string template"
Elemer Lelik's avatar
Elemer Lelik committed
%token <charstring_val> Cstring MPCstring "charstring value"
%token <str_val> UIDval
%token DNSName "hostname"
/* a single bit */
%token <logseverity_val> LoggingBit
/* a collection of bits */
%token <logseverity_val>  LoggingBitCollection
%token SubCategories
%token <emergency_logging_behaviour_value> EmergencyLoggingBehaviourValue "BufferAll or BufferMasked"
%token <timestamp_value> TimestampValue "Time, Datetime or Seconds"
%token <source_info_value> SourceInfoValue "None, Single or Stack"
%token <bool_val> YesNo "yes or no"
%token LocalAddress
%token TCPPort
%token KillTimer
%token NumHCs
%token UnixSocketEnabled
%token YesToken "yes"
%token NoToken  "no"
%token LogFileSize
%token LogFileNumber
%token DiskFullAction
%token MatchingHints
%token LoggerPlugins
%token Error
%token Stop
%token Retry
%token Delete
%token TtcnStringParsingKeyword
Elemer Lelik's avatar
Elemer Lelik committed
%token DisableProfilerKeyword    "DisableProfiler"
%token DisableCoverageKeyword    "DisableCoverage"
%token DatabaseFileKeyword       "DatabaseFile"
%token AggregateDataKeyword      "AggregateData"
%token StatisticsFileKeyword     "StatisticsFile"
%token DisableStatisticsKeyword  "DisableStatistics"
%token StatisticsFilterKeyword   "StatisticsFilter"
%token StartAutomaticallyKeyword "StartAutomatically"
%token NetLineTimesKeyword       "NetLineTimes"
%token NetFunctionTimesKeyword   "NetFunctionTimes"
%token <uint_val> ProfilerStatsFlag "profiler statistics filter"

%type <int_val> IntegerValue
%type <float_val> FloatValue
%type <objid_val> ObjIdValue ObjIdComponentList
%type <int_val> ObjIdComponent NumberForm NameAndNumberForm

Elemer Lelik's avatar
Elemer Lelik committed
%type <universal_charstring_val> UniversalCharstringValue UniversalCharstringFragment
%type <universal_char_val> Quadruple
%type <uid_list> USI UIDlike

%type <str_val> LoggerPluginId
%type <logging_plugins> LoggerPlugin LoggerPluginList
%type <logging_params> LoggingParam
%type <logging_param_line> LoggingParamLines
%type <str_val> LogFileName StringValue
/* a collection of bits */
%type <logoptions_val> LoggingBitmask
%type <logoptions_val> LoggingBitOrCollection
%type <source_info_value> SourceInfoSetting
%type <bool_val> YesNoOrBoolean
%type <log_event_types_value> LogEventTypesValue
%type <disk_full_action_value> DiskFullActionValue
%type <str_val> Command
%type <matching_verbosity_value> VerbosityValue
%type <comp_id> ComponentId
%type <str_val> TestportName ArrayRef TestportParameterName
	TestportParameterValue

%type <execute_item_val> ExecuteItem

%type <bitstring_val> BitstringValue
%type <hexstring_val> HexstringValue
%type <octetstring_val> OctetstringValue

%type <name_vector> ParameterName ParameterNameSegment
%type <param_optype_val> ParamOpType
%type <str_val> FieldName
%type <module_param_val> ParameterValue SimpleParameterValue ParameterValueOrNotUsedSymbol
  FieldValue ArrayItem IndexItem IndexItemList FieldValueList ArrayItemList CompoundValue IntegerRange FloatRange StringRange
Elemer Lelik's avatar
Elemer Lelik committed
  ParameterExpression ParameterReference
%type <module_param_list> TemplateItemList
%type <module_param_length_restriction> LengthMatch
Elemer Lelik's avatar
Elemer Lelik committed
%type <str_val> PatternChunk
%type <int_native> IndexItemIndex LengthBound
Elemer Lelik's avatar
Elemer Lelik committed
%type <uint_val> ProfilerStatsFlags

%destructor { Free($$); }
ArrayRef
ASN1LowerIdentifier
Command
FieldName
Identifier
LogFileName
StringValue
TestportName
TestportParameterName
TestportParameterValue
PatternChunk
BstringMatch
HstringMatch
OstringMatch

%destructor { Free($$.components_ptr); }
ObjIdComponentList
ObjIdValue

%destructor { Free($$.bits_ptr); }
Bstring
BitstringValue

%destructor { Free($$.nibbles_ptr); }
Hstring
HexstringValue

%destructor { Free($$.octets_ptr); }
Ostring
OctetstringValue

%destructor { Free($$.chars_ptr); }
Cstring
Elemer Lelik's avatar
Elemer Lelik committed
MPCstring
Elemer Lelik's avatar
Elemer Lelik committed
%destructor { Free($$.uchars_ptr); }
UniversalCharstringFragment
UniversalCharstringValue

%destructor { if ($$.id_selector == COMPONENT_ID_NAME) Free($$.id_name); }
ComponentId

%destructor { Free($$.module_name); Free($$.testcase_name); }
ExecuteItem

%destructor { delete $$; }
IntegerValue
NameAndNumberForm
Number
Elemer Lelik's avatar
Elemer Lelik committed
MPNumber
NumberForm
ObjIdComponent
ParameterValue
SimpleParameterValue
ParameterValueOrNotUsedSymbol
ArrayItemList
FieldValueList
IndexItemList
CompoundValue
ArrayItem
FieldValue
IndexItem
IntegerRange
FloatRange
StringRange
Elemer Lelik's avatar
Elemer Lelik committed
ParameterExpression
ParameterReference

%destructor { delete $$; }
LengthMatch

%destructor { for(size_t i=0; i<$$->size(); i++) { delete $$->at(i); } delete $$; }
TemplateItemList

%destructor { for(size_t i=0; i<$$->size(); i++) { Free($$->at(i)); } delete $$; }
ParameterName
ParameterNameSegment

Elemer Lelik's avatar
Elemer Lelik committed
%left '&' /* to avoid shift/reduce conflicts */
%left '+' '-'
%left '*' '/'
%left UnarySign

Elemer Lelik's avatar
Elemer Lelik committed
%expect 1
Elemer Lelik's avatar
Elemer Lelik committed
1 conflict:
When seeing a '*' token after a module parameter expression the parser cannot
decide whether the token is a multiplication operator (shift) or it refers to 
all modules in the next module parameter (reduce).
*/
%%

GrammarRoot:
  ConfigFile
  {
    if (Ttcn_String_Parsing::happening()) {
      config_process_error("Config file cannot be parsed as ttcn string");
    }
  }
| TtcnStringParsingKeyword ParameterValue
  {
    parsed_module_param = $2;
  }
;

ConfigFile:
	/* empty */
	| ConfigFile Section
;

Section:
	ModuleParametersSection
	| LoggingSection
Elemer Lelik's avatar
Elemer Lelik committed
  | ProfilerSection
	| TestportParametersSection
	| ExecuteSection
	| ExternalCommandsSection
	| GroupsSection
	| ComponentsSection
	| MainControllerSection
	| IncludeSection
	| DefineSection
;

ModuleParametersSection:
	ModuleParametersKeyword ModuleParameters
;

ModuleParameters:
	/* empty */
	| ModuleParameters ModuleParameter optSemiColon
;

ModuleParameter:
	ParameterName ParamOpType ParameterValue
{
  Module_Param* mp = $3;
  mp->set_id(new Module_Param_Name(*$1));
  mp->set_operation_type($2);
  set_param(*mp);
  delete mp;
  delete $1;
}
;

ParameterName:
  ParameterNameSegment            { $$ = $1; }
| '*' '.' ParameterNameSegment    { $$ = $3; }
;

ParameterNameSegment:
	ParameterNameSegment '.' Identifier
{
  $$ = $1;
  $$->push_back($3);
}
Elemer Lelik's avatar
Elemer Lelik committed
| ParameterNameSegment IndexItemIndex
Elemer Lelik's avatar
Elemer Lelik committed
  $$->push_back(mprintf("%d", $2));
}
| Identifier
{
  $$ = new Vector<char*>();
  $$->push_back($1); 
}
;

ParameterValue:
Elemer Lelik's avatar
Elemer Lelik committed
  ParameterExpression
Elemer Lelik's avatar
Elemer Lelik committed
| ParameterExpression LengthMatch
  {
    $$ = $1;
    $$->set_length_restriction($2);
  }
Elemer Lelik's avatar
Elemer Lelik committed
| ParameterExpression IfpresentKeyword
  {
    $$ = $1;
    $$->set_ifpresent();
  }
Elemer Lelik's avatar
Elemer Lelik committed
| ParameterExpression LengthMatch IfpresentKeyword
  {
    $$ = $1;
    $$->set_length_restriction($2);
    $$->set_ifpresent();
  }
;

LengthMatch:
  LengthKeyword '(' LengthBound ')'
  {
    $$ = new Module_Param_Length_Restriction();
    $$->set_single((size_t)$3);
  }
| LengthKeyword '(' LengthBound DotDot LengthBound ')'
  {
    if ($3>$5) {
      config_process_error("invalid length restriction: lower bound > upper bound");
    }
    $$ = new Module_Param_Length_Restriction();
    $$->set_min((size_t)$3);
    $$->set_max((size_t)$5);
  }
| LengthKeyword '(' LengthBound DotDot InfinityKeyword ')'
  {
    $$ = new Module_Param_Length_Restriction();
    $$->set_min((size_t)$3);
  }
;

LengthBound:
Elemer Lelik's avatar
Elemer Lelik committed
  ParameterExpression
Elemer Lelik's avatar
Elemer Lelik committed
  $1->set_id(new Module_Param_CustomName(mcopystr("length bound")));
  INTEGER tmp;
  tmp.set_param(*$1);
  if (!tmp.get_val().is_native()) {
    config_process_error("bignum length restriction bound.");
    $$ = 0;
Elemer Lelik's avatar
Elemer Lelik committed
  } else if (tmp.get_val().is_negative()) {
    config_process_error("negative length restriction bound.");
    $$ = 0;
  } else {
Elemer Lelik's avatar
Elemer Lelik committed
    $$ = tmp;
Elemer Lelik's avatar
Elemer Lelik committed
// one global rule for expressions in module parameters
// the expression's result will be calculated by set_param()
ParameterExpression:
  SimpleParameterValue { $$ = $1; }
| ParameterReference { $$ = $1; }
| '(' ParameterExpression ')' { $$ = $2; }
| '+' ParameterExpression %prec UnarySign { $$ = $2; }
| '-' ParameterExpression %prec UnarySign { $$ = new Module_Param_Expression($2); }
| ParameterExpression '+' ParameterExpression
  {
    $$ = new Module_Param_Expression(Module_Param::EXPR_ADD, $1, $3);
  }
| ParameterExpression '-' ParameterExpression
  {
    $$ = new Module_Param_Expression(Module_Param::EXPR_SUBTRACT, $1, $3);
  }
| ParameterExpression '*' ParameterExpression
  {
    $$ = new Module_Param_Expression(Module_Param::EXPR_MULTIPLY, $1, $3);
  }
| ParameterExpression '/' ParameterExpression
  {
    $$ = new Module_Param_Expression(Module_Param::EXPR_DIVIDE, $1, $3);
  }
| ParameterExpression '&' ParameterExpression
  {
    $$ = new Module_Param_Expression(Module_Param::EXPR_CONCATENATE, $1, $3);
  }
;

ParameterReference:
  // enumerated values are also treated as references by the parser,
  // these will be sorted out later during set_param()
  ParameterNameSegment
  {
    $$ = new Module_Param_Reference(new Module_Param_Name(*$1));
  }
;

SimpleParameterValue:
Elemer Lelik's avatar
Elemer Lelik committed
	MPNumber
  {
    $$ = new Module_Param_Integer($1);
  }
Elemer Lelik's avatar
Elemer Lelik committed
| MPFloat
  {
    $$ = new Module_Param_Float($1);
  }
| BooleanValue
  {
    $$ = new Module_Param_Boolean($1);
  }
| ObjIdValue
  {
    $$ = new Module_Param_Objid($1.n_components, $1.components_ptr);
  }
| VerdictValue
  {
    $$ = new Module_Param_Verdict($1);
  }
| BitstringValue
  {
    $$ = new Module_Param_Bitstring($1.n_bits, $1.bits_ptr);
  }
| HexstringValue
  {
    $$ = new Module_Param_Hexstring($1.n_nibbles, $1.nibbles_ptr);
  }
| OctetstringValue
  {
    $$ = new Module_Param_Octetstring($1.n_octets, $1.octets_ptr);
  }
Elemer Lelik's avatar
Elemer Lelik committed
| MPCstring
  {
    $$ = new Module_Param_Charstring($1.n_chars, $1.chars_ptr);
  }
| UniversalCharstringValue
  {
Elemer Lelik's avatar
Elemer Lelik committed
    $$ = new Module_Param_Universal_Charstring($1.n_uchars, $1.uchars_ptr);
  }
| OmitKeyword
  {
    $$ = new Module_Param_Omit();
  }
| NULLKeyword
  {
    $$ = new Module_Param_Asn_Null();
  }
| nullKeyword
  {
    $$ = new Module_Param_Ttcn_Null();
  }
| MTCKeyword
  {
    $$ = new Module_Param_Ttcn_mtc();
  }
| SystemKeyword
  {
    $$ = new Module_Param_Ttcn_system();
  }
| '?'
  {
    $$ = new Module_Param_Any();
  }
| '*'
  {
    $$ = new Module_Param_AnyOrNone();
  }
| IntegerRange
  {
    $$ = $1;
  }
| FloatRange
  {
    $$ = $1;
  }
| StringRange
  {
    $$ = $1;
  }
Elemer Lelik's avatar
Elemer Lelik committed
| PatternKeyword PatternChunk
  {
    $$ = new Module_Param_Pattern($2);
  }
| BstringMatch
  {
    // conversion
    int n_chars = (int)mstrlen($1);
    unsigned char* chars_ptr = (unsigned char*)Malloc(n_chars*sizeof(unsigned char));
    for (int i=0; i<n_chars; i++) {
      switch ($1[i]) {
      case '0':
        chars_ptr[i] = 0;
        break;
      case '1':
        chars_ptr[i] = 1;
        break;
      case '?':
        chars_ptr[i] = 2;
        break;
      case '*':
        chars_ptr[i] = 3;
        break;
      default:
        chars_ptr[i] = 0;
        config_process_error_f("Invalid char (%c) in bitstring template", $1[i]);
      }
    }
    Free($1);
    $$ = new Module_Param_Bitstring_Template(n_chars, chars_ptr);
  }
| HstringMatch
  {
    int n_chars = (int)mstrlen($1);
    unsigned char* chars_ptr = (unsigned char*)Malloc(n_chars*sizeof(unsigned char));
    for (int i=0; i<n_chars; i++) {
      if ($1[i]=='?') chars_ptr[i] = 16;
      else if ($1[i]=='*') chars_ptr[i] = 17;
      else chars_ptr[i] = char_to_hexdigit($1[i]);
    }
    Free($1);
    $$ = new Module_Param_Hexstring_Template(n_chars, chars_ptr);
  }
| OstringMatch
  {
    Vector<unsigned short> octet_vec;
    int str_len = (int)mstrlen($1);
    for (int i=0; i<str_len; i++) {
      unsigned short num;
      if ($1[i]=='?') num = 256;
      else if ($1[i]=='*') num = 257;
      else {
        // first digit
        num = 16 * char_to_hexdigit($1[i]);
        i++;
        if (i>=str_len) config_process_error("Unexpected end of octetstring pattern");
        // second digit
        num += char_to_hexdigit($1[i]);
      }
      octet_vec.push_back(num);
    }
    Free($1);
    int n_chars = (int)octet_vec.size();
    unsigned short* chars_ptr = (unsigned short*)Malloc(n_chars*sizeof(unsigned short));
    for (int i=0; i<n_chars; i++) chars_ptr[i] = octet_vec[i];
    $$ = new Module_Param_Octetstring_Template(n_chars, chars_ptr);
  }
| CompoundValue
  {
    $$ = $1;
  }
;

PatternChunk:
Elemer Lelik's avatar
Elemer Lelik committed
  MPCstring
  {
    $$ = mcopystr($1.chars_ptr);
    Free($1.chars_ptr);
  }
| Quadruple
  {
    $$ = mprintf("\\q{%d,%d,%d,%d}", $1.uc_group, $1.uc_plane, $1.uc_row, $1.uc_cell);
  }
;

IntegerRange:
Elemer Lelik's avatar
Elemer Lelik committed
  '(' '-' InfinityKeyword DotDot MPNumber ')'
  {
    $$ = new Module_Param_IntRange(NULL, $5);
  }
Elemer Lelik's avatar
Elemer Lelik committed
| '(' MPNumber DotDot MPNumber ')'
  {
    $$ = new Module_Param_IntRange($2, $4);
  }
Elemer Lelik's avatar
Elemer Lelik committed
| '(' MPNumber DotDot InfinityKeyword ')'
  {
    $$ = new Module_Param_IntRange($2, NULL);
  }
;

FloatRange:
Elemer Lelik's avatar
Elemer Lelik committed
  '(' '-' InfinityKeyword DotDot MPFloat ')'
  {
    $$ = new Module_Param_FloatRange(0.0, false, $5, true);
  }
Elemer Lelik's avatar
Elemer Lelik committed
| '(' MPFloat DotDot MPFloat ')'
  {
    $$ = new Module_Param_FloatRange($2, true, $4, true);
  }
Elemer Lelik's avatar
Elemer Lelik committed
| '(' MPFloat DotDot InfinityKeyword ')'
  {
    $$ = new Module_Param_FloatRange($2, true, 0.0, false);
  }
;

StringRange:
  '(' UniversalCharstringFragment DotDot UniversalCharstringFragment ')'
  {
    universal_char lower; lower.uc_group=lower.uc_plane=lower.uc_row=lower.uc_cell=0;
    universal_char upper; upper.uc_group=upper.uc_plane=upper.uc_row=upper.uc_cell=0;
    if ($2.n_uchars!=1) {
      config_process_error("Lower bound of char range must be 1 character only");
    } else if ($4.n_uchars!=1) {
      config_process_error("Upper bound of char range must be 1 character only");
    } else {
      lower = *($2.uchars_ptr);
      upper = *($4.uchars_ptr);
      if (upper<lower) {
        config_process_error("Lower bound is larger than upper bound in the char range");
        lower = upper;
      }
    }
    Free($2.uchars_ptr);
    Free($4.uchars_ptr);
    $$ = new Module_Param_StringRange(lower, upper);
  }
;

Elemer Lelik's avatar
Elemer Lelik committed
// integers outside of the [MODULE_PARAMETERS] section
IntegerValue:
	Number { $$ = $1; }
	| '(' IntegerValue ')' { $$ = $2; }
	| '+' IntegerValue %prec UnarySign { $$ = $2; }
  | '-' IntegerValue %prec UnarySign
{
  INTEGER op1;
  op1.set_val(*$2);
  $$ = new int_val_t((-op1).get_val());
  delete $2;
}
  | IntegerValue '+' IntegerValue
{
  INTEGER op1, op2;
  op1.set_val(*$1);
  op2.set_val(*$3);
  $$ = new int_val_t((op1 + op2).get_val());
  delete $1;
  delete $3;
}
  | IntegerValue '-' IntegerValue
{
  INTEGER op1, op2;
  op1.set_val(*$1);
  op2.set_val(*$3);
  $$ = new int_val_t((op1 - op2).get_val());
  delete $1;
  delete $3;
}
  | IntegerValue '*' IntegerValue
{
  INTEGER op1, op2;
  op1.set_val(*$1);
  op2.set_val(*$3);
  $$ = new int_val_t((op1 * op2).get_val());
  delete $1;
  delete $3;
}
  | IntegerValue '/' IntegerValue
{
  if (*$3 == 0) {
    config_process_error("Integer division by zero.");
    $$ = new int_val_t((RInt)0);
    delete $1;
    delete $3;
  } else {
    INTEGER op1, op2;
    op1.set_val(*$1);
    op2.set_val(*$3);
    $$ = new int_val_t((op1 / op2).get_val());
    delete $1;
    delete $3;
  }
}
;

Elemer Lelik's avatar
Elemer Lelik committed
// floats outside of the [MODULE_PARAMETERS] section
FloatValue:
	Float { $$ = $1; }
	| '(' FloatValue ')' { $$ = $2; }
	| '+' FloatValue %prec UnarySign { $$ = $2; }
	| '-' FloatValue %prec UnarySign { $$ = -$2; }
	| FloatValue '+' FloatValue { $$ = $1 + $3; }
	| FloatValue '-' FloatValue { $$ = $1 - $3; }
	| FloatValue '*' FloatValue { $$ = $1 * $3; }
	| FloatValue '/' FloatValue
{
	if ($3 == 0.0) {
		config_process_error("Floating point division by zero.");
		$$ = 0.0;
	} else $$ = $1 / $3;
}
;

ObjIdValue:
	ObjIdKeyword '{' ObjIdComponentList '}' { $$ = $3; }
;

ObjIdComponentList:
	ObjIdComponent
{
	$$.n_components = 1;
	$$.components_ptr = (int *)Malloc(sizeof(int));
	$$.components_ptr[0] = $1->get_val();
	delete $1;
}
	| ObjIdComponentList ObjIdComponent
{
	$$.n_components = $1.n_components + 1;
	$$.components_ptr = (int *)Realloc($1.components_ptr,
		$$.n_components * sizeof(int));
	$$.components_ptr[$$.n_components - 1] = $2->get_val();
	delete $2;
}
;

ObjIdComponent:
	NumberForm { $$ = $1; }
	| NameAndNumberForm { $$ = $1; }
;

NumberForm:
Elemer Lelik's avatar
Elemer Lelik committed
	MPNumber { $$ = $1; }
;

NameAndNumberForm:
Elemer Lelik's avatar
Elemer Lelik committed
	Identifier '(' MPNumber ')'
{
	Free($1);
	$$ = $3;
}
;

BitstringValue:
Elemer Lelik's avatar
Elemer Lelik committed
	Bstring { $$ = $1; }
;

HexstringValue:
Elemer Lelik's avatar
Elemer Lelik committed
	Hstring { $$ = $1; }
;

OctetstringValue:
Elemer Lelik's avatar
Elemer Lelik committed
	Ostring { $$ = $1; }
;

UniversalCharstringValue:
Elemer Lelik's avatar
Elemer Lelik committed
  Quadruple
{
	$$.n_uchars = 1;
	$$.uchars_ptr = (universal_char*)Malloc(sizeof(universal_char));
	$$.uchars_ptr[0] = $1;
}
  | USI
{
  $$.n_uchars = $1.nElements;
  $$.uchars_ptr = (universal_char*)Malloc($$.n_uchars * sizeof(universal_char));
  for (int i = 0; i < $$.n_uchars; ++i) {
    size_t offset = 1; //Always starts with u or U
    offset = $1.elements[i][1] == '+' ? offset + 1 : offset; //Optional '+'

    char* p;
    unsigned long int_val = strtoul($1.elements[i] + offset, &p, 16);
    if(*p != 0) {
      //Error, should not happen
      config_process_error_f("Invalid hexadecimal string %s.", $1.elements[i] + offset);
    }
    
    //Fill in the quadruple
    $$.uchars_ptr[i].uc_group = (int_val >> 24) & 0xFF;
    $$.uchars_ptr[i].uc_plane = (int_val >> 16) & 0xFF;
    $$.uchars_ptr[i].uc_row   = (int_val >> 8) & 0xFF;
    $$.uchars_ptr[i].uc_cell  = int_val & 0xFF;

    Free((char*)$1.elements[i]);
  }
  Free($1.elements);
}
;

UniversalCharstringFragment:
Elemer Lelik's avatar
Elemer Lelik committed
	MPCstring
{
	$$.n_uchars = $1.n_chars;
	$$.uchars_ptr = (universal_char*)
		Malloc($$.n_uchars * sizeof(universal_char));
	for (int i = 0; i < $1.n_chars; i++) {
		$$.uchars_ptr[i].uc_group = 0;
		$$.uchars_ptr[i].uc_plane = 0;
		$$.uchars_ptr[i].uc_row = 0;
		$$.uchars_ptr[i].uc_cell = $1.chars_ptr[i];
	}
	Free($1.chars_ptr);
}
	| Quadruple
{
	$$.n_uchars = 1;
	$$.uchars_ptr = (universal_char*)Malloc(sizeof(universal_char));
	$$.uchars_ptr[0] = $1;
}
;

Quadruple:
Elemer Lelik's avatar
Elemer Lelik committed
	CharKeyword '(' ParameterExpression ',' ParameterExpression ','
  ParameterExpression ','	ParameterExpression ')'
Elemer Lelik's avatar
Elemer Lelik committed
  $3->set_id(new Module_Param_CustomName(mcopystr("quadruple group")));
  $5->set_id(new Module_Param_CustomName(mcopystr("quadruple plane")));
  $7->set_id(new Module_Param_CustomName(mcopystr("quadruple row")));
  $9->set_id(new Module_Param_CustomName(mcopystr("quadruple cell")));
  INTEGER g, p, r, c;
  g.set_param(*$3);
  p.set_param(*$5);
  r.set_param(*$7);
  c.set_param(*$9);
  if (g < 0 || g > 127) {
    char *s = g.get_val().as_string();
    config_process_error_f("The first number of quadruple (group) must be "
      "within the range 0 .. 127 instead of %s.", s);
    Free(s);
Elemer Lelik's avatar
Elemer Lelik committed
    $$.uc_group = g < 0 ? 0 : 127;
  } else {
Elemer Lelik's avatar
Elemer Lelik committed
    $$.uc_group = g;
Elemer Lelik's avatar
Elemer Lelik committed
  if (p < 0 || p > 255) {
    char *s = p.get_val().as_string();