/******************************************************************************
 * Copyright (c) 2000-2021 Ericsson Telecom AB
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
 *
 * Contributors:
 *   Balasko, Jeno
 *   Baranyi, Botond
 *   Raduly, Csaba
 *   Szabo, Janos Zoltan – initial implementation
 *   Szabo, Bence Janos
 *   Szalai, Gabor
 *   Zalanyi, Balazs Andor
 *
 ******************************************************************************/
/* RAW encoding/decoding specification parser & compiler */

%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../../common/memory.h"
#include "../Int.hh"
#include "../Real.hh"
#include "../Value.hh"
#include "AST_ttcn3.hh"
#include "rawASTspec.h"
#include "RawAST.hh"
#include "../XerAttributes.hh"
#include "BerAST.hh"
#include "JsonAST.hh"
#include "../main.hh"

extern void rawAST_error(const char *str);
extern int rawAST_lex();

extern RawAST* rawstruct;
extern Common::Module *mymod;
extern int length_multiplier;
extern Common::Type::MessageEncodingType_t selected_codec;
extern TextAST *textstruct;
extern bool raw_f;
extern bool text_f;
extern bool xer_f;
extern bool ber_f;
extern bool json_f;
extern XerAttributes* xerstruct;
extern BerAST* berstruct;
extern JsonAST* jsonstruct;

extern string *parse_charstring_value(const char *str,
  const Common::Location& loc);

#define YYERROR_VERBOSE

#ifndef NDEBUG
union YYSTYPE;
static void yyprint(FILE *file, int type, const YYSTYPE& value);
#define YYPRINT(f,t,v) yyprint(f,t,v)
#endif

%}

%union {
    bool boolval;
    int enumval;
    char* str;
    const char *cstr;
    Common::Int intval;
    Common::Real floatval;
    Common::Value::verdict_t verdictval;
    Common::Identifier *identifier;
    rawAST_field_list *fieldlist;
    rawAST_force_omit forceomit;
    rawAST_tag_list taglist;
    rawAST_tag_field_value keyid;
    rawAST_single_tag singletag;
    rawAST_toplevel toplevel;
    rawAST_values values;
    struct {
      char *token;
      bool case_sensitive;
    } decodetoken;
    NamespaceSpecification nsspec;
    NamespaceRestriction   nsrestr;
    struct {
      char* str;
      Ttcn::Reference* reference;
      bool ref;
    } dfestruct;
}

%token <intval> XNumber
%token <floatval> XFloatValue
%token <identifier> XIdentifier
%token <str> XBstring
%token <str> XHstring
%token <str> XOstring
%token <str> XCstring
%token <str> Xstring
%token <boolval> XBooleanConst
%token <verdictval> XVerdictConst
%token XNullKeyword
%token XNULLKeyword
%token XOmitKeyword

%token <str> Xtoken
%token XBeginKeyword
%token XEndKeyword
%token XSeparatorKeyword
%token XCodingKeyword
%token XLengthToken
%token XLowerToken
%token XUpperToken
%token XJustToken
%token XLeftToken
%token XRightToken
%token XCenterToken
%token XLeadingToken
%token XTrueToken
%token XSensitivToken
%token XInSensitivToken
%token XConvertToken
%token XFalseToken
%token XRepeatToken

%token XPaddingKeyword
%token XPaddAllKeyword
%token XPrePaddingKeyword
%token XPaddingPatternKeyword
%token XOtherwise
%token <enumval> XYes
%token <enumval> XNo
%token <enumval> XReverse
%token XFieldOrderKeyword
%token <enumval> XMsb
%token <enumval> XLsb
%token XExtensionBitKeyword
%token XExtensionBitGroupKeyword
%token XLengthToKeyword
%token XPointerToKeyword
%token XUnitKeyword
%token XPtrUnitKeyword
%token XPtrOffsetKeyword
%token <enumval> XBits
%token <enumval> XOctets
%token XLengthIndexKeyword
%token XTagKeyword
%token XCrossTagKeyword
%token XPresenceKeyword
%token XForceOmitKeyword
%token XFieldLengthKeyword
%token XAlignKeyword
%token <enumval> XLeft
%token <enumval> XRight
%token XCompKeyword
%token <enumval> XUnsigned
%token <enumval> XCompl
%token <enumval> XSignbit
%token XByteOrderKeyword
%token <enumval> XFirst
%token <enumval> XLast
%token XBitOrderKeyword
%token XBitOrderInFieldKeyword
%token XBitOrderInOctetKeyword
%token XHexOrderKeyword
%token <enumval> XLow
%token <enumval> XHigh
%token XToplevelKeyword
%token XRepeatableKeyword
%token XIntXKeyword
%token XBitKeyword
%token XUnsignedKeyword
%token XUTF8Keyword
%token XUTF16Keyword
%token XIEEE754FloatKeyword
%token XIEEE754DoubleKeyword
%token XCsn1LHKeyword "CSN.1 L/H"

       /* XER attributes */
%token XKWall           "all"
%token XKWas            "as"
%token XKWin            "in"
%token XKWcapitalized   "capitalized"
%token XKWuncapitalized "uncapitalized"
%token XKWlowercased    "lowercased"
%token XKWuppercased    "uppercased"
%token XKWpreserve      "preserve"
%token XKWreplace       "replace"
%token XKWcollapse      "collapse"
%token XKWfrom          "from"
%token XKWexcept        "except"
%token XKWunqualified   "unqualified"
%token XKWqualified     "qualified"
%token XKWprefix        "prefix"


%token XKWabstract         "abstact"
%token XKWanyAttributes    "anyAttributes"
%token XKWanyElement       "anyElement"
%token XKWattribute        "attribute"
%token XKWattributeFormQualified   "attributeFormQualified"
%token XKWblock            "block"
%token XKWcontrolNamespace "controlNamespace"
%token XKWdefaultForEmpty  "defaultForEmpty"
%token XKWelement          "element"
%token XKWelementFormQualified          "elementFormQualified"
%token XKWembedValues      "embedValues"
%token XKWform             "form"
%token XKWfractionDigits   "fractionDigits"
%token XKWlist             "list"
%token XKWname             "name"
%token XKWnamespace        "namespace"
%token XKWtext             "text"
%token XKWuntagged         "untagged"
%token XKWuseNil           "useNil"
%token XKWuseNumber        "useNumber"
%token XKWuseOrder         "useOrder"
%token XKWuseUnion         "useUnion"
%token XKWuseType          "useType"
%token XKWwhiteSpace       "whiteSpace"
%token XSD                 "XSD"

       /* XSD:something */
%token XSDstring "string"
%token XSDnormalizedString "normalizedString"
%token XSDtoken "token"
%token XSDName "Name"
%token XSDNMTOKEN "NMTOKEN"
%token XSDNCName "NCName"
%token XSDID "ID"
%token XSDIDREF "IDREF"
%token XSDENTITY "ENTITY"
%token XSDhexBinary "hexBinary"
%token XSDbase64Binary "base64Binary"
%token XSDanyURI "anyURI"
%token XSDlanguage "language"
%token XSDinteger "integer"
%token XSDpositiveInteger "positiveInteger"
%token XSDnonPositiveInteger "nonPositiveInteger"
%token XSDnegativeInteger "negativeInteger"
%token XSDnonNegativeInteger "nonNegativeInteger"
  /* XKWlong instead of %token XSDlong */
%token XSDunsignedLong "unsignedLong"
%token XSDint "int"
%token XSDunsignedInt "unsignedInt"
  /* XKWshort instead of %token XSDshort */
%token XSDunsignedShort "unsignedShort"
%token XSDbyte "byte"
%token XSDunsignedByte "unsignedByte"
%token XSDdecimal "decimal"
%token XSDfloat "float"
%token XSDdouble "double"
%token XSDduration "duration"
%token XSDdateTime "dateTime"
%token XSDtime "time"
%token XSDdate "date"
%token XSDgYearMonth "gYearMonth"
%token XSDgYear "gYear"
%token XSDgMonthDay "gMonthDay"
%token XSDgDay "gDay"
%token XSDgMonth "gMonth"
%token XSDNMTOKENS "NMTOKENS"
%token XSDIDREFS "IDREFS"
%token XSDENTITIES "ENTITIES"
%token XSDQName "QName"
%token XSDboolean "boolean"
%token XSDanySimpleType "anySimpleType"
%token XSDanyType "anyType"



/* BER attributes */
%token XKWlength     "length"
%token XKWaccept     "accept"
%token XKWlong       "long"
%token XKWshort      "short"
%token XKWindefinite "indefinite"
%token XKWdefinite   "definite"


// JSON attributes
%token XKWjson            "JSON"
%token XKWomit            "omit"
%token XKWnull            "null"
%token XAliasToken        "JSON alias"
%token XKWvalue           "value"
%token XKWdefault         "default"
%token XKWextend          "extend"
%token XKWmetainfo        "metainfo"
%token XKWfor             "for"
%token XKWunbound         "unbound"
%token XKWnumber          "number"
%token XKWinteger         "JSON:integer"
%token XKWstring          "JSON:string"
%token XKWarray           "JSON:array"
%token XKWobject          "JSON:object"
%token XKWobjectMember    "JSON:object member"
%token XKWliteral         "JSON:literal"
%token XJsonValueStart    "("
%token XJsonValueEnd      ")"
%token XJsonValueSegment  "JSON value"
%token XAsValueKeyword    "asValue"
%token XChosenKeyword     "chosen"
%token XJsonOtherwise     "otherwise"
%token XJsonMap           "map"
%token XKWescape          "escape"
%token XKWusi             "usi"
%token XKWtransparent     "transparent"


%type <enumval>
    XYesOrNo XMsbOrLsb XFieldOrderDef XPaddingDef XExtensionBitDef XUnitDef
    XBitsOctets XAlignDef XLeftOrRight XCompDef XCompValues XByteOrderDef
    XFirstOrLast XBitOrderDef XBitOrderInFieldDef XBitOrderInOctetDef
    XHexOrderDef XLowOrHigh XYesOrNoOrReverse XFieldLengthDef
    XPtrOffsetDef XPrePaddingDef XRepeatableDef form

%type <fieldlist>
    XLengthIndexDef XStructFieldRefOrEmpty XStructFieldRef

%type <forceomit>
    XStructFieldRefList

%type <str>
    XEncodeToken XmatchDef XAliasToken XJsonValueSegment XJsonValueCore XJsonValue
    XJsonAlias

%type <decodetoken>
    XDecodeToken

%type <cstr>
    XTextReservedWord

%type <identifier>
    XPointerToDef XRecordFieldRef XIdentifierOrReserved

%type <values>
    XRvalue

%type <taglist>
    XAssocList

/* note: multiple "XSingleEncodingDefs have to be merged into one 'fullspec' */
%type <fullspec>
    XEncodingDefList XSingleEncodingDef

%type <keyid>
    XKeyId
%type <boolval>
    XmodifierDef

%type <singletag>
    XAssocElement XKeyIdOrIdList XKeyIdList XMultiKeyId

%type <toplevel>
    XToplevelDef XTopDefList XTopDef

    /* XER */
%type <nsrestr>
    anyAttributes anyElement optNamespaceRestriction urilist


%type <str>  name newnameOrKeyword  keyword optPrefix quotedURIorAbsent

%type <dfestruct> defaultForEmpty

%type <nsspec> namespace namespacespecification controlNamespace text

%type <intval> whiteSpace fractionDigits

    /* destructors */
%destructor { Free($$); }
XBstring
XCstring
XEncodeToken
XHstring
XmatchDef
XOstring
Xtoken
Xstring
XAliasToken
XJsonAlias
XJsonValueSegment
XJsonValueCore
XJsonValue

%destructor { delete $$; }
XIdentifier
XIdentifierOrReserved
XPointerToDef
XRecordFieldRef

%destructor { free_rawAST_field_list($$); }
XLengthIndexDef
XStructFieldRef
XStructFieldRefOrEmpty

%destructor {
  for (int i = 0; i < $$.nElements; ++i) {
    free_rawAST_field_list($$.lists[i]);
  }
  Free($$.lists);
}
XStructFieldRefList

%destructor { free_rawAST_tag_list(&$$); }
XAssocList

%destructor { free_rawAST_tag_field_value(&$$); }
XKeyId

%destructor { free_rawAST_single_tag(&$$); }
XAssocElement
XKeyIdList
XKeyIdOrIdList
XMultiKeyId

%destructor {
  Free($$.value);
  delete $$.v_value;
}
XRvalue

%destructor { Free($$.token); }
XDecodeToken

%destructor {
  FreeNamespaceRestriction($$);
}
anyAttributes anyElement optNamespaceRestriction urilist

%destructor {
  Free($$.uri);
  Free($$.prefix);
}
namespace
namespacespecification
text
controlNamespace



%start XAttribSpec

%%

/* BNF, actions */

XAttribSpec : /* Empty */
    | XEncodingDefList
        { }
    | XERattributes
    	{ }
    | XBERattributes
        { }
    | JSONattributes
      { }
    ;

XBERattributes :
      XKWlength XKWaccept XKWshort { berstruct->decode_param = BerAST::LENGTH_ACCEPT_SHORT; ber_f=true; }
    | XKWlength XKWaccept XKWlong { berstruct->decode_param = BerAST::LENGTH_ACCEPT_LONG; ber_f=true; }
    | XKWlength XKWaccept XKWindefinite { berstruct->decode_param = BerAST::LENGTH_ACCEPT_INDEFINITE; ber_f=true; }
    | XKWlength XKWaccept XKWdefinite { berstruct->decode_param = BerAST::LENGTH_ACCEPT_DEFINITE; ber_f=true; }
;

XEncodingDefList : XSingleEncodingDef
        { }
    | XEncodingDefList ','  XSingleEncodingDef
        { };

XSingleEncodingDef : XPaddingDef
        { rawstruct->padding=$1;raw_f=true;}
    | XPrePaddingDef
        { rawstruct->prepadding=$1;raw_f=true;}
    | XPaddingPattern { raw_f=true;}
    | XPaddAll { rawstruct->paddall=XDEFYES;raw_f=true;}
    | XFieldOrderDef
        { rawstruct->fieldorder=$1;raw_f=true;}
    | XExtensionBitDef
        { rawstruct->extension_bit=$1;raw_f=true;}
    | XExtensionBitGroupDef
        { raw_f=true;}
    | XLengthToDef
        { raw_f=true;}
    | XPointerToDef
        { delete rawstruct->pointerto;
          rawstruct->pointerto = $1;
          raw_f=true;
        }
    | XUnitDef
        { rawstruct->unit=$1; raw_f=true;}
    | XLengthIndexDef
        { free_rawAST_field_list(rawstruct->lengthindex);
          rawstruct->lengthindex = $1;raw_f=true; }
    | XTagDef
        {raw_f=true; }
    | XCrossTagDef
        {raw_f=true; }
    | XPresenceDef
        { raw_f=true;}
    | XForceOmitDef
        { raw_f = true; }
    | XFieldLengthDef
        { rawstruct->fieldlength = $1*length_multiplier; raw_f=true;}
    | XPtrOffsetDef
        { raw_f=true; }
    | XAlignDef
        { rawstruct->align = $1; raw_f=true;}
    | XCompDef
        { rawstruct->comp = $1;raw_f=true; }
    | XByteOrderDef
        { rawstruct->byteorder = $1; raw_f=true;}
    | XBitOrderInFieldDef
        { rawstruct->bitorderinfield = $1; raw_f=true;}
    | XBitOrderInOctetDef
        { rawstruct->bitorderinoctet = $1; raw_f=true;}
    | XHexOrderDef
        { rawstruct->hexorder = $1;raw_f=true; }
    | XRepeatableDef
        { rawstruct->repeatable = $1;raw_f=true; }
    | XToplevelDef
        { rawstruct->topleveleind=1; raw_f=true;}
    | XIntXKeyword
        { rawstruct->intx = true; raw_f = true; }
    | XBitDef
        { raw_f = true; }
    | XUTFDef
        { raw_f = true; }
    | XIEEE754Def
        { raw_f = true; }
    | XCsn1LHDef
        { raw_f = true; }
    /* TEXT encoder keywords */
    | XBeginDef
        { text_f=true; }
    | XEndDef
        { text_f=true; }
    | XSeparatorDef
        { text_f=true; }
    | XCodingDef
        { text_f=true; }
    | XJsonDef
        { json_f = true; }
    ;

XRepeatableDef : XRepeatableKeyword '(' XYesOrNo ')'  { $$ = $3; }

/* Padding*/
XPaddingDef : XPaddingKeyword '(' XYesOrNo ')'  { $$ = $3==XDEFYES?8:0; }
           | XPaddingKeyword '(' XBitsOctets ')'  { $$ = $3;};
XPrePaddingDef : XPrePaddingKeyword '(' XYesOrNo ')'  { $$ = $3==XDEFYES?8:0; }
           | XPrePaddingKeyword '(' XBitsOctets ')'  { $$ = $3;};
XYesOrNo : XYes | XNo;

XPaddingPattern:
  XPaddingPatternKeyword '(' XBstring ')'
  {
    Free(rawstruct->padding_pattern);
    size_t len = strlen($3);
    if (len > 0) {
      rawstruct->padding_pattern = mcopystr($3);
      rawstruct->padding_pattern_length = len;
      while (rawstruct->padding_pattern_length % 8 != 0) {
	rawstruct->padding_pattern = mputstr(rawstruct->padding_pattern, $3);
	rawstruct->padding_pattern_length += len;
      }
    } else rawstruct->padding_pattern = NULL;
    Free($3);
  }
;

XPaddAll:  XPaddAllKeyword
/* FieldOrder */
XFieldOrderDef : XFieldOrderKeyword '(' XMsbOrLsb ')'
        { $$ = $3; };
XMsbOrLsb : XMsb | XLsb;

/* Extension bit */
XExtensionBitDef : XExtensionBitKeyword '(' XYesOrNoOrReverse ')'
        { $$ = $3; };
XYesOrNoOrReverse : XYes | XNo | XReverse;

XExtensionBitGroupDef: XExtensionBitGroupKeyword '(' XYesOrNoOrReverse ','
                       XIdentifier ',' XIdentifier ')'
        { if(rawstruct->ext_bit_goup_num==0){
            rawstruct->ext_bit_groups=
                    (rawAST_ext_bit_group*)Malloc(sizeof(rawAST_ext_bit_group));
            rawstruct->ext_bit_goup_num=1;
          } else{
            rawstruct->ext_bit_goup_num++;
            rawstruct->ext_bit_groups=(rawAST_ext_bit_group*)
                 Realloc(rawstruct->ext_bit_groups,
                      rawstruct->ext_bit_goup_num*sizeof(rawAST_ext_bit_group));
          }
          rawstruct->ext_bit_groups[rawstruct->ext_bit_goup_num-1].ext_bit=$3;
          rawstruct->ext_bit_groups[rawstruct->ext_bit_goup_num-1].from=$5;
          rawstruct->ext_bit_groups[rawstruct->ext_bit_goup_num-1].to=$7;
        }

/* LengthTo */
XLengthToDef : XLengthToKeyword '(' XRecordFieldRefList ')'
        {  }
| XLengthToKeyword '(' XRecordFieldRefList ')' '+' XNumber
{ rawstruct->lengthto_offset = $6; }

| XLengthToKeyword '(' XRecordFieldRefList ')' '-' XNumber
{ rawstruct->lengthto_offset = -$6; }
;

/* PointerTo */
XPointerToDef : XPointerToKeyword '(' XRecordFieldRef ')'
        { $$ = $3; };

/* Unit */
XUnitDef : XUnitKeyword '(' XBitsOctets ')' { $$ = $3; }
         | XPtrUnitKeyword '(' XBitsOctets ')' { $$ = $3; };
XBitsOctets : XBits {$$=$1;}
          | XOctets {$$=$1;}
          | XNumber {$$=$1;};

/* LengthIndex */
XLengthIndexDef : XLengthIndexKeyword '(' XStructFieldRefOrEmpty ')'
        { $$ = $3; };


/* Tag, Crosstag */
XTagDef : XTagKeyword '(' XAssocList XoptSemiColon ')'
        { free_rawAST_tag_list(&(rawstruct->taglist));
          link_rawAST_tag_list(&(rawstruct->taglist),&$3);};
XCrossTagDef : XCrossTagKeyword '(' XAssocList XoptSemiColon ')'
        { free_rawAST_tag_list(&(rawstruct->crosstaglist));
          link_rawAST_tag_list(&(rawstruct->crosstaglist),&$3);};

XAssocList:
  XAssocElement
  {
    $$.nElements = 1;
    $$.tag = (rawAST_single_tag*)Malloc(sizeof(*$$.tag));
    link_rawAST_single_tag($$.tag, &$1);
  }
| XAssocList XSemiColon XAssocElement
  {
    int dupl_id_index = -1;
    if ($3.nElements > 0) {
      /* the otherwise element is never merged */
      for (int i = 0; i < $1.nElements; i++)
	if (($1.tag[i].fieldName == NULL && $3.fieldName == NULL) ||
	    ($1.tag[i].fieldName != NULL && $3.fieldName != NULL &&
	     *$1.tag[i].fieldName == *$3.fieldName)) {
	  dupl_id_index = i;
	  break;
	}
    }
    if (dupl_id_index >= 0) {
      /* this identifier is already specified in XAssocList
	 merge the new parameters to the existing entry */
      $$ = $1;
      rawAST_single_tag *tag = $$.tag + dupl_id_index;
      tag->keyList = (rawAST_tag_field_value*)
	Realloc(tag->keyList, (tag->nElements + $3.nElements)
	  * sizeof(*tag->keyList));
      memcpy(tag->keyList + tag->nElements, $3.keyList,
	$3.nElements * sizeof(*$3.keyList));
      tag->nElements += $3.nElements;
      delete $3.fieldName;
      Free($3.keyList);
    } else {
      $$.nElements = $1.nElements + 1;
      $$.tag = (rawAST_single_tag*)
	Realloc($1.tag, $$.nElements * sizeof(*$$.tag));
      $$.tag[$1.nElements] = $3;
    }
  }
;

XSemiColon:
  ';'
;

XoptSemiColon:
  /* Empty */
| ';'
;

XAssocElement:
  XIdentifier ',' XKeyIdOrIdList
  {
    $$.fieldName = $1;
    $$.nElements = $3.nElements;
    $$.keyList = $3.keyList;
  }
| XIdentifier ',' XOtherwise
  {
    $$.fieldName = $1;
    $$.nElements = 0;
    $$.keyList = NULL;
  }
| XIdentifier ',' XJsonOtherwise // JSON version
  {
    $$.fieldName = $1;
    $$.nElements = 0;
    $$.keyList = NULL;
  }
| XOmitKeyword ',' XKeyIdOrIdList
  {
    $$.fieldName = NULL;
    $$.nElements = $3.nElements;
    $$.keyList = $3.keyList;
  }
| XOmitKeyword ',' XOtherwise
  {
    $$.fieldName = NULL;
    $$.nElements = 0;
    $$.keyList = NULL;
  }
| XOmitKeyword ',' XJsonOtherwise // JSON version
  {
    $$.fieldName = NULL;
    $$.nElements = 0;
    $$.keyList = NULL;
  }
;

XKeyIdOrIdList:
  XKeyId
  {
    $$.fieldName = NULL;
    $$.nElements = 1;
    $$.keyList = (rawAST_tag_field_value*)Malloc(sizeof(*$$.keyList));
    $$.keyList[0] = $1;
  }
| XKeyIdList { $$ = $1; }
;

XKeyIdList:
  '{' XMultiKeyId '}' { $$ = $2; }
;

XMultiKeyId:
  XKeyId
  {
    $$.fieldName = NULL;
    $$.nElements = 1;
    $$.keyList = (rawAST_tag_field_value*)Malloc(sizeof(*$$.keyList));
    $$.keyList[0] = $1;
  }
| XMultiKeyId ',' XKeyId
  {
    $$.fieldName = NULL;
    $$.nElements = $1.nElements + 1;
    $$.keyList = (rawAST_tag_field_value*)
      Realloc($1.keyList, $$.nElements * sizeof(*$$.keyList));
    $$.keyList[$1.nElements] = $3;
  }
;

XKeyId:
  XStructFieldRef '=' XRvalue
  {
    $$.keyField = $1;
    $$.value = $3.value;
    $$.v_value = $3.v_value;
  }
;

/* Presence */
XPresenceDef : XPresenceKeyword '(' XKeyIdList XoptSemiColon ')'
        { free_rawAST_single_tag(&(rawstruct->presence));
        link_rawAST_single_tag(&(rawstruct->presence), &$3);}
        | XPresenceKeyword '(' XMultiKeyId XoptSemiColon ')'
        { free_rawAST_single_tag(&(rawstruct->presence));
        link_rawAST_single_tag(&(rawstruct->presence), &$3);};

/* ForceOmit */
XForceOmitDef:
  XForceOmitKeyword '(' XStructFieldRefList ')'
  {
    if (rawstruct->forceomit.nElements == 0) {
      rawstruct->forceomit = $3;
    }
    else {
      rawstruct->forceomit.lists = static_cast<rawAST_field_list**>(
        Realloc(rawstruct->forceomit.lists,
        (rawstruct->forceomit.nElements + $3.nElements) *
        sizeof(rawAST_field_list*)));
      memcpy(rawstruct->forceomit.lists + rawstruct->forceomit.nElements,
        $3.lists, $3.nElements * sizeof(rawAST_field_list*));
      rawstruct->forceomit.nElements += $3.nElements;
      Free($3.lists);
    }
  }
;

XStructFieldRefList:
  XStructFieldRef
  {
    $$.nElements = 1;
    $$.lists = static_cast<rawAST_field_list**>(
      Malloc(sizeof(rawAST_field_list*)) );
    $$.lists[0] = $1;
  }
| XStructFieldRefList ',' XStructFieldRef
  {
    $$.nElements = $1.nElements + 1;
    $$.lists = static_cast<rawAST_field_list**>(
      Realloc($1.lists, $$.nElements * sizeof(rawAST_field_list*)) );
    $$.lists[$1.nElements] = $3;
  }
;

/* FieldLength */
XFieldLengthDef : XFieldLengthKeyword '(' XNumber ')'
        { $$ = $3;};

/* PtrOffset */
XPtrOffsetDef : XPtrOffsetKeyword '(' XNumber ')'
        { rawstruct->ptroffset = $3; }
        |XPtrOffsetKeyword '(' XIdentifier ')'
        {
	  delete rawstruct->ptrbase;
	  rawstruct->ptrbase = $3;
        }
/* Align */
XAlignDef : XAlignKeyword '(' XLeftOrRight ')'
        { $$ = $3; };
XLeftOrRight : XLeft | XRight;

/* Comp */
XCompDef : XCompKeyword '(' XCompValues ')'
        { $$ = $3; };
XCompValues : XUnsigned | XCompl | XSignbit;

/* ByteOrder */
XByteOrderDef : XByteOrderKeyword '(' XFirstOrLast ')'
        { $$ = $3; };
XFirstOrLast : XFirst | XLast;

/* BitOrder */
XBitOrderInFieldDef : XBitOrderInFieldKeyword '(' XMsbOrLsb ')'
        { $$ = $3; };
XBitOrderInOctetDef : XBitOrderInOctetKeyword '(' XMsbOrLsb ')'
        { $$ = $3; }
        | XBitOrderKeyword '(' XMsbOrLsb ')' { $$ = $3; };
XToplevelDef : XToplevelKeyword '(' XTopDefList ')'
        { };
XTopDefList : XTopDef
        { }
    | XTopDefList ',' XTopDef
        {  };
XTopDef : XBitOrderDef
        { rawstruct->toplevel.bitorder = $1;};
XBitOrderDef : XBitOrderKeyword '(' XMsbOrLsb ')'
        { $$ = $3; };

/* HexOrder */
XHexOrderDef : XHexOrderKeyword '(' XLowOrHigh ')'
        { $$ = $3; };
XLowOrHigh : XLow | XHigh;

/* General types */
/* FieldRefList */
XRecordFieldRefList : XRecordFieldRef
        { rawstruct->lengthto_num = 1;
          rawstruct->lengthto =
                  (Common::Identifier**)Malloc(sizeof(*(rawstruct->lengthto)));
          rawstruct->lengthto[0] = $1;
        }
    | XRecordFieldRefList ',' XRecordFieldRef
        { rawstruct->lengthto_num++;
          rawstruct->lengthto =
                 (Common::Identifier**)Realloc(rawstruct->lengthto,
                       rawstruct->lengthto_num*sizeof(*(rawstruct->lengthto)));
          rawstruct->lengthto[rawstruct->lengthto_num - 1] = $3;
          }
;

XRecordFieldRef : XIdentifier
        { $$ = $1; };

XStructFieldRefOrEmpty : /* Empty */
        { $$ = NULL;}
    | XStructFieldRef
        { $$ = $1; };

XStructFieldRef : XIdentifier
        { $$ = (rawAST_field_list*)Malloc(sizeof(*$$));
          $$->nElements=1;
          $$->names = (Common::Identifier**)Malloc(sizeof(*($$->names)));
          $$->names[0] = $1;
        }
    | XStructFieldRef '.' XIdentifier
        { $$ = $1;
	  $$->nElements++;
          $$->names = (Common::Identifier**)
                      Realloc($$->names, $$->nElements*sizeof(*($$->names)));
          $$->names[$$->nElements - 1] = $3;
	}
;

XRvalue: XIdentifier{
        $$.value = mcopystr($1->get_name().c_str());
        $$.v_value = new Common::Value(Common::Value::V_UNDEF_LOWERID, $1);
        $$.v_value->set_location(infile, @$);
      }
    | XBstring{
        string *str= new string($1);
        $$.value=mprintf(" %s", mymod->add_bitstring_literal(*str).c_str());
        $$.v_value=new Common::Value(Common::Value::V_BSTR,str);
        $$.v_value->set_location(infile, @$);
        Free($1);
      }
    | XHstring{
        string *str= new string($1);
        $$.value=mprintf(" %s", mymod->add_hexstring_literal(*str).c_str());
        $$.v_value=new Common::Value(Common::Value::V_HSTR,str);
        $$.v_value->set_location(infile, @$);
        Free($1);
      }

    | XOstring{
        string *str= new string($1);
        $$.value=mprintf(" %s", mymod->add_octetstring_literal(*str).c_str());
        $$.v_value=new Common::Value(Common::Value::V_OSTR,str);
        $$.v_value->set_location(infile, @$);
        Free($1);
      }
    | XCstring{
	Common::Location loc(infile, @$);
	string *str = parse_charstring_value($1, loc);
	Free($1);
        $$.value=mprintf(" %s", mymod->add_charstring_literal(*str).c_str());
        $$.v_value=new Common::Value(Common::Value::V_CSTR,str);
        $$.v_value->set_location(loc);
      }
    | XFloatValue{
        $$.value=mcopystr(Common::Real2code($1).c_str());
        $$.v_value=new Common::Value(Common::Value::V_REAL, $1);
        $$.v_value->set_location(infile, @$);
      }
    | XNumber{
        $$.value = mcopystr(Common::Int2string($1).c_str());
        $$.v_value=new Common::Value(Common::Value::V_INT, $1);
        $$.v_value->set_location(infile, @$);
      }
    | XBooleanConst
      {
        $$.value = mcopystr($1 ? "TRUE" : "FALSE");
        $$.v_value=new Common::Value(Common::Value::V_BOOL, $1);
        $$.v_value->set_location(infile, @$);
      }
    | XVerdictConst
      {
	$$.v_value = new Common::Value(Common::Value::V_VERDICT, $1);
        $$.v_value->set_location(infile, @$);
	$$.value = mcopystr($$.v_value->get_single_expr().c_str());
      }
    | XNullKeyword
      {
	$$.value = mcopystr("NULL_COMPREF");
	$$.v_value = new Common::Value(Common::Value::V_TTCN3_NULL);
        $$.v_value->set_location(infile, @$);
      }
    | XNULLKeyword
      {
	$$.value = mcopystr("ASN_NULL_VALUE");
	$$.v_value = new Common::Value(Common::Value::V_NULL);
        $$.v_value->set_location(infile, @$);
      }
    | XOmitKeyword
      {
	$$.value = mcopystr("OMIT_VALUE");
	$$.v_value = new Common::Value(Common::Value::V_OMIT);
	$$.v_value->set_location(infile, @$);
      }
;

/* Alternative RAW attributes for types defined in annex E of the TTCN-3 standard */
XBitDef:
  XNumber XBitKeyword
  {
    rawstruct->fieldlength = $1;
    rawstruct->comp = XDEFSIGNBIT;
    rawstruct->byteorder = XDEFLAST;
  }
| XUnsignedKeyword XNumber XBitKeyword
  {
    rawstruct->fieldlength = $2;
    rawstruct->comp = XDEFUNSIGNED;
    rawstruct->byteorder = XDEFLAST;
  }
;

XUTFDef:
  XUTF8Keyword { rawstruct->stringformat = CharCoding::UTF_8; }
| XUTF16Keyword { rawstruct->stringformat = CharCoding::UTF16; }

XIEEE754Def:
  XIEEE754FloatKeyword { rawstruct->fieldlength = 32; }
| XIEEE754DoubleKeyword { rawstruct->fieldlength = 64; }

XCsn1LHDef:
  XCsn1LHKeyword { rawstruct->csn1lh = true; }

/* Text encoder */
XBeginDef:
    XBeginKeyword '(' XEncodeToken ')' {
       if(textstruct->begin_val==NULL){
          textstruct->begin_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->begin_val);
        }
        Free(textstruct->begin_val->encode_token);
        textstruct->begin_val->encode_token=$3;
      }
    | XBeginKeyword '(' XEncodeToken ',' XmatchDef ')' {
       if(textstruct->begin_val==NULL){
          textstruct->begin_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->begin_val);
        }
        Free(textstruct->begin_val->encode_token);
        textstruct->begin_val->encode_token=$3;
        if($5){
          Free(textstruct->begin_val->decode_token);
          textstruct->begin_val->decode_token=$5;
        }
      }
    | XBeginKeyword '(' XEncodeToken ',' XmatchDef ',' XmodifierDef ')'{
       if(textstruct->begin_val==NULL){
          textstruct->begin_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->begin_val);
        }
        Free(textstruct->begin_val->encode_token);
        textstruct->begin_val->encode_token=$3;
        if($5){
          Free(textstruct->begin_val->decode_token);
          textstruct->begin_val->decode_token=$5;
        }
        textstruct->begin_val->case_sensitive=$7;
      }
;

XEndDef:
    XEndKeyword '(' XEncodeToken ')' {
       if(textstruct->end_val==NULL){
          textstruct->end_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->end_val);
        }
        Free(textstruct->end_val->encode_token);
        textstruct->end_val->encode_token=$3;
      }
    | XEndKeyword '(' XEncodeToken ',' XmatchDef ')'{
       if(textstruct->end_val==NULL){
          textstruct->end_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->end_val);
        }
        Free(textstruct->end_val->encode_token);
        textstruct->end_val->encode_token=$3;
        if($5){
          Free(textstruct->end_val->decode_token);
          textstruct->end_val->decode_token=$5;
        }
      }
    | XEndKeyword '(' XEncodeToken ',' XmatchDef ',' XmodifierDef ')'{
       if(textstruct->end_val==NULL){
          textstruct->end_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->end_val);
        }
        Free(textstruct->end_val->encode_token);
        textstruct->end_val->encode_token=$3;
        if($5){
          Free(textstruct->end_val->decode_token);
          textstruct->end_val->decode_token=$5;
        }
        textstruct->end_val->case_sensitive=$7;
      }
;

XSeparatorDef:
    XSeparatorKeyword '(' XEncodeToken ')'{
       if(textstruct->separator_val==NULL){
          textstruct->separator_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->separator_val);
        }
        Free(textstruct->separator_val->encode_token);
        textstruct->separator_val->encode_token=$3;
      }
    | XSeparatorKeyword '(' XEncodeToken ',' XmatchDef ')'{
       if(textstruct->separator_val==NULL){
          textstruct->separator_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->separator_val);
        }
        Free(textstruct->separator_val->encode_token);
        textstruct->separator_val->encode_token=$3;
        if($5){
          Free(textstruct->separator_val->decode_token);
          textstruct->separator_val->decode_token=$5;
        }
      }
    | XSeparatorKeyword '(' XEncodeToken ',' XmatchDef ',' XmodifierDef ')'{
       if(textstruct->separator_val==NULL){
          textstruct->separator_val=(textAST_matching_values*)
                                        Malloc(sizeof(textAST_matching_values));
          init_textAST_matching_values(textstruct->separator_val);
        }
        Free(textstruct->separator_val->encode_token);
        textstruct->separator_val->encode_token=$3;
        if($5){
          Free(textstruct->separator_val->decode_token);
          textstruct->separator_val->decode_token=$5;
        }
        textstruct->separator_val->case_sensitive=$7;
      }
;

XCodingDef:
    XCodingKeyword '(' XCodingRule ')'
        { }
    | XCodingKeyword '(' XCodingRule ',' XDecodingRule ')'
        { }
    | XCodingKeyword '(' XCodingRule ',' XDecodingRule ',' XmatchDef ')' {
          Free(textstruct->decode_token);
          textstruct->decode_token=$7;
        }
    | XCodingKeyword '(' XCodingRule ',' XDecodingRule ',' XmatchDef ','
                                                           XmodifierDef ')' {
          if($7){
            Free(textstruct->decode_token);
            textstruct->decode_token=$7;
          }
          textstruct->case_sensitive=$9;
        }
;

XCodingRule:
    /* empty */ {}
    | Xattrlistenc {}
    | XtokendefList {}
;

XDecodingRule:
    /* empty */ {}
    | XattrList {}
    | XDecodingtokendefList {}
;

XattrList:
   Xattr {}
   | XattrList ';' Xattr {}
;

Xattr:
   XLengthToken '=' XNumber {
     textstruct->decoding_params.min_length=$3;
   }
   | XLengthToken '=' XNumber '-' XNumber {
     textstruct->decoding_params.min_length=$3;
     textstruct->decoding_params.max_length=$5;
   }
   | XConvertToken '=' XLowerToken {
     textstruct->decoding_params.convert=-1;
   }
   | XConvertToken '=' XUpperToken {
     textstruct->decoding_params.convert=1;
   }
   | XJustToken '=' XLeftToken {
     textstruct->decoding_params.just=-1;
   }
   | XJustToken '=' XRightToken {
     textstruct->decoding_params.just=1;
   }
   | XJustToken '=' XCenterToken {
     textstruct->decoding_params.just=0;
   }
   | XLeadingToken '=' XTrueToken {
     textstruct->decoding_params.leading_zero=true;
   }
   | XLeadingToken '=' XFalseToken {
     textstruct->decoding_params.leading_zero=false;
   }
   | XRepeatToken '=' XTrueToken {
     textstruct->decoding_params.repeatable=true;
   }
   | XRepeatToken '=' XFalseToken {
     textstruct->decoding_params.repeatable=false;
   };

Xattrlistenc:
   Xattrenc {}
   | Xattrlistenc ';' Xattrenc {}
;

Xattrenc:
   XLengthToken '=' XNumber {
     textstruct->coding_params.min_length=$3;
     textstruct->decoding_params.min_length=$3;
   }
   | XLengthToken '=' XNumber '-' XNumber {
     textstruct->coding_params.min_length=$3;
     textstruct->coding_params.max_length=$5;
     textstruct->decoding_params.min_length=$3;
     textstruct->decoding_params.max_length=$5;
   }
   | XConvertToken '=' XLowerToken {
     textstruct->coding_params.convert=-1;
     textstruct->decoding_params.convert=-1;
   }
   | XConvertToken '=' XUpperToken {
     textstruct->coding_params.convert=1;
     textstruct->decoding_params.convert=1;
   }
   | XJustToken '=' XLeftToken {
     textstruct->coding_params.just=-1;
     textstruct->decoding_params.just=-1;
   }
   | XJustToken '=' XRightToken {
     textstruct->coding_params.just=1;
     textstruct->decoding_params.just=1;
   }
   | XJustToken '=' XCenterToken {
     textstruct->coding_params.just=0;
     textstruct->decoding_params.just=0;
   }
   | XLeadingToken '=' XTrueToken {
     textstruct->coding_params.leading_zero=true;
     textstruct->decoding_params.leading_zero=true;
   }
   | XLeadingToken '=' XFalseToken {
     textstruct->coding_params.leading_zero=false;
     textstruct->decoding_params.leading_zero=false;
   }
   | XRepeatToken '=' XTrueToken {
     textstruct->coding_params.repeatable=true;
     textstruct->decoding_params.repeatable=true;
   }
   | XRepeatToken '=' XFalseToken {
     textstruct->coding_params.repeatable=false;
     textstruct->decoding_params.repeatable=false;
   };


XtokendefList:
   Xtokendef {}
   | XtokendefList ';' Xtokendef {}
;

Xtokendef:
  XIdentifierOrReserved ':' XEncodeToken
  {
    size_t idx = textstruct->get_field_param_index($1);
    if (textstruct->field_params[idx]->value.encode_token) {
      Free(textstruct->field_params[idx]->value.encode_token);
      Common::Location loc(infile, @3);
      loc.error("Duplicate encode token for value `%s'",
	$1->get_dispname().c_str());
    }
    textstruct->field_params[idx]->value.encode_token = $3;
    delete $1;
  }
| XTrueToken ':' XEncodeToken
  {
    if (textstruct->true_params == NULL) {
      textstruct->true_params = (textAST_matching_values*)
	Malloc(sizeof(textAST_matching_values));
      textstruct->true_params->encode_token = $3;
      textstruct->true_params->decode_token = NULL;
      textstruct->true_params->case_sensitive = true;
      textstruct->true_params->generated_decode_token = false;
    } else {
      if (textstruct->true_params->encode_token) {
	Free(textstruct->true_params->encode_token);
	Common::Location loc(infile, @3);
	loc.error("Duplicate encode token for true value");
      }
      textstruct->true_params->encode_token = $3;
    }
  }
| XFalseToken ':' XEncodeToken
  {
    if (textstruct->false_params == NULL) {
      textstruct->false_params = (textAST_matching_values*)
	Malloc(sizeof(textAST_matching_values));
      textstruct->false_params->encode_token = $3;
      textstruct->false_params->decode_token = NULL;
      textstruct->false_params->case_sensitive = true;
      textstruct->false_params->generated_decode_token = false;
    } else {
      if (textstruct->false_params->encode_token) {
	Free(textstruct->false_params->encode_token);
	Common::Location loc(infile, @3);
	loc.error("Duplicate encode token for false value");
      }
      textstruct->false_params->encode_token = $3;
    }
  }
;

XIdentifierOrReserved:
  XIdentifier { $$ = $1; }
| XTextReservedWord
  { $$ = new Common::Identifier(Common::Identifier::ID_TTCN, string($1)); }
;

XTextReservedWord:
  XLengthToken { $$ = "length"; }
| XRepeatToken { $$ = "repeatable"; }
| XConvertToken { $$ = "convert"; }
| XLowerToken { $$ = "lower_case"; }
| XUpperToken { $$ = "upper_case"; }
| XJustToken { $$ = "just"; }
| XLeftToken { $$ = "left"; }
| XRightToken { $$ = "right"; }
| XCenterToken { $$ = "center"; }
| XLeadingToken { $$ = "leading0"; }
| XSensitivToken { $$ = "case_sensitive"; }
| XInSensitivToken { $$ = "case_insensitive"; }
;

XDecodingtokendefList:
    Xdecodingtokendef  {}
   |  XDecodingtokendefList ';' Xdecodingtokendef {}
;

Xdecodingtokendef:
  XIdentifierOrReserved ':' XDecodeToken
  {
    size_t idx = textstruct->get_field_param_index($1);
    if (textstruct->field_params[idx]->value.decode_token) {
      Free(textstruct->field_params[idx]->value.decode_token);
      Common::Location loc(infile, @3);
      loc.error("Duplicate decode token for value `%s'",
	$1->get_dispname().c_str());
    }
    textstruct->field_params[idx]->value.decode_token = $3.token;
    textstruct->field_params[idx]->value.case_sensitive = $3.case_sensitive;
    delete $1;
  }
| XTrueToken ':' XDecodeToken
  {
    if (textstruct->true_params == NULL) {
      textstruct->true_params = (textAST_matching_values*)
	Malloc(sizeof(textAST_matching_values));
      textstruct->true_params->encode_token = NULL;
      textstruct->true_params->decode_token = $3.token;
      textstruct->true_params->case_sensitive = $3.case_sensitive;
      textstruct->true_params->generated_decode_token = false;
    } else {
      if (textstruct->true_params->decode_token) {
	Free(textstruct->true_params->decode_token);
	Common::Location loc(infile, @3);
	loc.error("Duplicate decode token for true value");
      }
      textstruct->true_params->decode_token = $3.token;
      textstruct->true_params->case_sensitive = $3.case_sensitive;
    }
  }
| XFalseToken ':' XDecodeToken
  {
    if (textstruct->false_params == NULL) {
      textstruct->false_params = (textAST_matching_values*)
	Malloc(sizeof(textAST_matching_values));
      textstruct->false_params->encode_token = NULL;
      textstruct->false_params->decode_token= $3.token;
      textstruct->false_params->case_sensitive = $3.case_sensitive;
      textstruct->false_params->generated_decode_token = false;
    } else {
      if (textstruct->false_params->decode_token) {
	Free(textstruct->false_params->decode_token);
	Common::Location loc(infile, @3);
	loc.error("Duplicate decode token for false value");
      }
      textstruct->false_params->decode_token = $3.token;
      textstruct->false_params->case_sensitive = $3.case_sensitive;
    }
  }
;

XEncodeToken:
  Xtoken
  {
    Common::Location loc(infile, @$);
    string *str = parse_charstring_value($1, loc);
    Free($1);
    $$ = mcopystr(str->c_str());
    delete str;
  }
;

XDecodeToken:
  Xtoken
  {
    $$.token = $1;
    $$.case_sensitive = true;
  }
| '{' Xtoken '}'
  {
    $$.token = $2;
    $$.case_sensitive = true;
  }
| '{' XmatchDef ',' XmodifierDef '}'
  {
    $$.token = $2;
    $$.case_sensitive = $4;
  }
;

XmatchDef:
  /* empty */ { $$ = NULL; }
| Xtoken { $$ = $1; }
;

XmodifierDef:
  /* empty */ { $$ = true; }
| XSensitivToken { $$ = true; }
| XInSensitivToken { $$ = false; }
;

	/********** XERSTUFF "raw" attributes */

XERattributes: /* a non-empty list */
    XERattribute { xer_f = true; }
    ;

XERattribute:
    XKWabstract { xerstruct->abstract_ = true; }
    | anyAttributes { FreeNamespaceRestriction(xerstruct->anyAttributes_); xerstruct->anyAttributes_ = $1; }
    | anyElement  { FreeNamespaceRestriction(xerstruct->anyElement_); xerstruct->anyElement_ = $1; }
    | XKWattribute  { xerstruct->attribute_ = true; }
    | XKWattributeFormQualified { xerstruct->form_ |= XerAttributes::ATTRIBUTE_DEFAULT_QUALIFIED; }
    | XKWblock { xerstruct->block_ = true; }
    | controlNamespace /* directly on the module */
      {
        mymod->set_controlns($1.uri, $1.prefix);
      }
    | defaultForEmpty
      {
        xerstruct->defaultForEmpty_ = $1.str;
        xerstruct->defaultForEmptyIsRef_ = $1.ref;
        xerstruct->defaultForEmptyRef_ = $1.reference;
      }
    | XKWelement { xerstruct->element_ = true; }
    | XKWelementFormQualified { xerstruct->form_ |= XerAttributes::ELEMENT_DEFAULT_QUALIFIED; }
    | XKWembedValues { xerstruct->embedValues_ = true; }
    | form { xerstruct->form_ |= $1; }
    | fractionDigits { xerstruct->fractionDigits_ = $1; xerstruct->has_fractionDigits_ = true; }
    | XKWlist { xerstruct->list_ = true; }
    | name
      { 
        // this handles the "name as '...' " attributes for both the XER and
        // JSON codecs
        // (overwrites any previously set name)
        if (selected_codec == Common::Type::CT_XER || legacy_codec_handling) {
          switch (xerstruct->name_.kw_) {
          case NamespaceSpecification::NO_MANGLING:
          case NamespaceSpecification::CAPITALIZED:
          case NamespaceSpecification::UNCAPITALIZED:
          case NamespaceSpecification::UPPERCASED:
          case NamespaceSpecification::LOWERCASED:
            break; // nothing to do
          default: // real string, must be freed
            Free(xerstruct->name_.nn_);
          }
          xerstruct->name_.nn_ = $1;
        }
        if (selected_codec != Common::Type::CT_XER) {
          // treat XML special values and real strings separately
          XerAttributes::NameChange special;
          special.nn_ = $1;
          switch (special.kw_) {
          case NamespaceSpecification::NO_MANGLING:
          case NamespaceSpecification::CAPITALIZED:
          case NamespaceSpecification::UNCAPITALIZED:
          case NamespaceSpecification::UPPERCASED:
          case NamespaceSpecification::LOWERCASED:
            // it's a special value
            // JSON: display an error (if using the new codec handling)
            // otherwise ignore
            if (!legacy_codec_handling &&
                selected_codec == Common::Type::CT_JSON) {
              Common::Location loc(infile, @$);
              loc.error("This format is not supported for the JSON codec");
            }
            break;
          default: // it's a real string
            if (selected_codec == Common::Type::CT_JSON ||
                legacy_codec_handling) {
              Free(jsonstruct->alias);
              if (legacy_codec_handling) {
                // in this case the string is saved in both the XML and JSON
                // structs, so we can't use the same string
                jsonstruct->alias = mcopystr($1);
              }
              else {
                jsonstruct->alias = $1;
              }
              json_f = true;
            }
            else {
              Free($1);
            }
            break;
          }
        }
      }
    | namespace
      { /* overwrites any previous namespace */
        Free(xerstruct->namespace_.uri);
        Free(xerstruct->namespace_.prefix);
        xerstruct->namespace_ = $1;
      }
    | text
      {
        if (selected_codec == Common::Type::CT_XER || legacy_codec_handling) {
          xerstruct->text_ = (NamespaceSpecification *)Realloc(xerstruct->text_,
            ++xerstruct->num_text_ * sizeof(NamespaceSpecification));
          xerstruct->text_[xerstruct->num_text_-1] = $1;
        }
        if (selected_codec != Common::Type::CT_XER) {
          boolean error = $1.prefix == (const char*)NamespaceSpecification::ALL;
          XerAttributes::NameChange special;
          special.nn_ = $1.uri;
          switch (special.kw_) {
          case NamespaceSpecification::NO_MANGLING:
          case NamespaceSpecification::CAPITALIZED:
          case NamespaceSpecification::UNCAPITALIZED:
          case NamespaceSpecification::UPPERCASED:
          case NamespaceSpecification::LOWERCASED:
            if (!error && !legacy_codec_handling) {
              // prefix is a real string, uri is a special value
              Free($1.prefix);
            }
            error = true;
            break;
          default: // it's a real string
            if (error && !legacy_codec_handling) {
              // prefix is a special value, uri is a real string
              Free($1.uri);
            }
          }
          if (error && !legacy_codec_handling) {
            Common::Location loc(infile, @$);
            loc.error("This format is not supported for the JSON codec");
            json_f = true;
          }
          if (!error) {
            if (selected_codec == Common::Type::CT_JSON ||
                legacy_codec_handling) {
              if (legacy_codec_handling) {
                // in this case the strings are saved in both the XML and JSON
                // structs, so we can't use the same strings
                jsonstruct->enum_texts.add(
                  new JsonEnumText(mcopystr($1.prefix), mcopystr($1.uri)));
              }
              else {
                jsonstruct->enum_texts.add(
                  new JsonEnumText($1.prefix, $1.uri));
              }
              json_f = true;
            }
            else {
              Free($1.prefix);
              Free($1.uri);
            }
            break;
          }
        }
      }
    | XKWuntagged  { xerstruct->untagged_  = true; }
    | XKWuseNil    { xerstruct->useNil_    = true; }
    | XKWuseNumber { xerstruct->useNumber_ = true; }
    | XKWuseOrder  { xerstruct->useOrder_  = true; }
    | XKWuseUnion  { xerstruct->useUnion_  = true; }
    | XKWuseType   { xerstruct->useType_   = true; }
    | whiteSpace
      {
        xerstruct->whitespace_ = static_cast<XerAttributes::WhitespaceAction>($1);
      }
    |   XSD ':' xsddata {}
    ;

anyAttributes:
    XKWanyAttributes optNamespaceRestriction
    { $$ = $2; }
    ;

anyElement:
    XKWanyElement optNamespaceRestriction
    { $$ = $2; }
    ;

optNamespaceRestriction:
    /* empty */ {
      $$.nElements_ = 0; $$.uris_ = 0; $$.type_ = NamespaceRestriction::NOTHING;
    }
    | XKWfrom   urilist { $$ = $2; $$.type_ = NamespaceRestriction::FROM; }
    | XKWexcept urilist { $$ = $2; $$.type_ = NamespaceRestriction::EXCEPT; }
    ;

urilist: /* a non-empty list */
    quotedURIorAbsent {
      $$.nElements_ = 1;
      $$.uris_ = (char**)Malloc(sizeof($$.uris_[0]));
      $$.uris_[0] = $1;
    }
    | urilist ',' quotedURIorAbsent
    {
      $$ = $1;
      $$.uris_ = (char**)Realloc($$.uris_, ++$$.nElements_ * sizeof($$.uris_[0]));
      $$.uris_[$$.nElements_-1] = $3;
    }
    ;

quotedURIorAbsent:
    Xstring /* as quotedURI */
    | XKWunqualified { $$ = NULL; }
    ;

controlNamespace: /* nsspec */
    XKWcontrolNamespace Xstring /* <-- as the QuotedURI */ XKWprefix Xstring
    /* Prefix is required by TTCN-3; it is optional in the ASN.1 standard
     * but the OSS ASN.1 compiler seems to require it anyway */
    {
      $$.uri = $2;
      $$.prefix = $4;
    }
    ;


form:
    XKWform XKWas XKWunqualified { $$ = XerAttributes::UNQUALIFIED; }
    | XKWform XKWas XKWqualified { $$ = XerAttributes::QUALIFIED; }


name:
    XKWname XKWas newnameOrKeyword { $$ = $3; }
    ;

newnameOrKeyword: keyword
| Xstring { $$ = $1; }
;

keyword:
XKWcapitalized     { $$ = (char*)NamespaceSpecification::CAPITALIZED; }
| XKWuncapitalized { $$ = (char*)NamespaceSpecification::UNCAPITALIZED; }
| XKWlowercased    { $$ = (char*)NamespaceSpecification::LOWERCASED; }
| XKWuppercased    { $$ = (char*)NamespaceSpecification::UPPERCASED; }
;

namespace:
    XKWnamespace namespacespecification
    { $$ = $2; }
;

namespacespecification:
    XKWas
    Xstring /* as QuotedURI, required */
    optPrefix
    {
      if (*$2) {
        $$.uri = $2; $$.prefix = $3;
      }
      else { /* URI is empty */
        if (*$3) { /* prefix not empty, error */
          Common::Location loc(infile, @2);
          loc.error("Empty string is not a valid URI");
        }
        else {
          /* Both are empty strings, use one of the non-string values
           * to signal "override and remove any namespace" */
          Free($2);
          Free($3);
          $$.keyword = NamespaceSpecification::UNCAPITALIZED;
          $$.prefix = NULL;
        }
      }
    }
;

optPrefix: /* empty */ { $$ = memptystr(); }
|    XKWprefix Xstring
    { $$ = $2; }
;

text:
    XKWtext Xstring XKWas newnameOrKeyword
    { $$.uri = $4; $$.prefix = $2; }
    | XKWtext XKWall  XKWas newnameOrKeyword
    { $$.uri = $4; $$.prefix = (char*)NamespaceSpecification::ALL; }
    | XKWtext
    { $$.uri = 0; $$.prefix = 0; }
    /* "text as <something>" is not allowed */
    ;

defaultForEmpty:
    XKWdefaultForEmpty XKWas Xstring
    { $$.str = $3; $$.ref = false; $$.reference = NULL; }
    | XKWdefaultForEmpty XKWas XIdentifier
    { $$.reference = new Ttcn::Reference($3);
      $$.reference->set_location(infile, @$);
      $$.ref = true;
      $$.str = NULL;
    }
    | XKWdefaultForEmpty XKWas XIdentifier '.' XIdentifier
    { $$.reference = new Ttcn::Reference($3, $5);
      $$.reference->set_location(infile, @$);
      $$.ref = true;
      $$.str = NULL;
    }
;

fractionDigits:
   XKWfractionDigits XNumber
   { $$ = $2; } 



whiteSpace:
    XKWwhiteSpace XKWpreserve { $$ = XerAttributes::PRESERVE; }
|   XKWwhiteSpace XKWreplace  { $$ = XerAttributes::REPLACE; }
|   XKWwhiteSpace XKWcollapse { $$ = XerAttributes::COLLAPSE; }
;

xsddata: /* XSD:something */
    XSDbase64Binary {
      xerstruct->base64_ = true;
      xerstruct->xsd_type = XSD_BASE64BINARY;
    }
    | XSDdecimal {
      xerstruct->decimal_ = true;
      xerstruct->xsd_type = XSD_DECIMAL;
    }
    | XSDhexBinary {
      xerstruct->hex_ = true;
      xerstruct->xsd_type = XSD_HEXBINARY;
    }
    | XSDQName {
      xerstruct->useQName_ = true;
      xerstruct->xsd_type = XSD_QNAME;
    }
    /* everything below is recognized */
    | XKWshort { xerstruct->xsd_type = XSD_SHORT; }
    | XKWlong { xerstruct->xsd_type = XSD_LONG; }
    | XSDstring           { xerstruct->xsd_type = XSD_STRING; }
    | XSDnormalizedString { xerstruct->xsd_type = XSD_NORMALIZEDSTRING; }
    | XSDtoken            { xerstruct->xsd_type = XSD_TOKEN; }
    | XSDName             { xerstruct->xsd_type = XSD_NAME; }
    | XSDNMTOKEN          { xerstruct->xsd_type = XSD_NMTOKEN; }
    | XSDNCName           { xerstruct->xsd_type = XSD_NCName; }
    | XSDID               { xerstruct->xsd_type = XSD_ID; }
    | XSDIDREF            { xerstruct->xsd_type = XSD_IDREF; }
    | XSDENTITY           { xerstruct->xsd_type = XSD_ENTITY; }
    | XSDanyURI           { xerstruct->xsd_type = XSD_ANYURI; }
    | XSDlanguage         { xerstruct->xsd_type = XSD_LANGUAGE; }
    /* TODO apply subtype to the types below */
    | XSDinteger          { xerstruct->xsd_type = XSD_INTEGER; }
    | XSDpositiveInteger  { xerstruct->xsd_type = XSD_POSITIVEINTEGER; }
    | XSDnonPositiveInteger { xerstruct->xsd_type = XSD_NONPOSITIVEINTEGER; }
    | XSDnegativeInteger { xerstruct->xsd_type = XSD_NEGATIVEINTEGER; }
    | XSDnonNegativeInteger { xerstruct->xsd_type = XSD_NONNEGATIVEINTEGER; }
    | XSDunsignedLong     { xerstruct->xsd_type = XSD_UNSIGNEDLONG; }
    | XSDint              { xerstruct->xsd_type = XSD_INT; }
    | XSDunsignedInt      { xerstruct->xsd_type = XSD_UNSIGNEDINT; }
    | XSDunsignedShort    { xerstruct->xsd_type = XSD_UNSIGNEDSHORT; }
    | XSDbyte             { xerstruct->xsd_type = XSD_BYTE; }
    | XSDunsignedByte     { xerstruct->xsd_type = XSD_UNSIGNEDBYTE; }
    | XSDfloat            { xerstruct->xsd_type = XSD_FLOAT; }
    | XSDdouble           { xerstruct->xsd_type = XSD_DOUBLE; }
    | XSDduration         { xerstruct->xsd_type = XSD_DURATION; }
    | XSDdateTime         { xerstruct->xsd_type = XSD_DATETIME; }
    | XSDtime             { xerstruct->xsd_type = XSD_TIME; }
    | XSDdate             { xerstruct->xsd_type = XSD_DATE; }
    | XSDgYearMonth       { xerstruct->xsd_type = XSD_GYEARMONTH; }
    | XSDgYear            { xerstruct->xsd_type = XSD_GYEAR; }
    | XSDgMonthDay        { xerstruct->xsd_type = XSD_GMONTHDAY; }
    | XSDgDay             { xerstruct->xsd_type = XSD_GDAY; }
    | XSDgMonth           { xerstruct->xsd_type = XSD_GMONTH; }
    // XSD:NMTOKENS, XSD:IDREFS and XSD:ENTIITES should behave it they have list variant
    | XSDNMTOKENS
    { 
      xerstruct->xsd_type = XSD_NMTOKENS;
      xerstruct->list_ = true;
    }
    | XSDIDREFS
    { 
      xerstruct->xsd_type = XSD_IDREFS;
      xerstruct->list_ = true;
    }
    | XSDENTITIES
    { 
      xerstruct->xsd_type = XSD_ENTITIES;
      xerstruct->list_ = true;
    }
    | XSDboolean          { xerstruct->xsd_type = XSD_BOOLEAN; }

    | XSDanySimpleType    { xerstruct->xsd_type = XSD_ANYSIMPLETYPE; }
    | XSDanyType          { xerstruct->xsd_type = XSD_ANYTYPE; }

;

// JSON attributes, with 'JSON:' prefix (legacy attributes and type indicators)
XJsonDef:
  XOptSpaces XKWjson XOptSpaces ':' XOptSpaces XJsonAttribute XOptSpaces
;

XJsonAttribute:
  XOmitAsNull 
| XNameAs
| XAsValue
| XDefault
| XExtend
| XMetainfoForUnbound
| XAsNumber
| XTypeIndicator
;

XOmitAsNull:
  XKWomit XSpaces XKWas XSpaces XKWnull { jsonstruct->omit_as_null = true; }
;

XNameAs:
  XKWname XSpaces XKWas XSpaces XJsonAlias {
    Free(jsonstruct->alias);
    jsonstruct->alias = $5;
  }
;

XJsonAlias: // include all keywords, so they can be used as aliases for fields, too
  XAliasToken { $$ = $1; }
| XKWomit     { $$ = mcopystr("omit"); }
| XKWas       { $$ = mcopystr("as"); }
| XKWnull     { $$ = mcopystr("null"); }
| XKWname     { $$ = mcopystr("name"); }
| XKWvalue    { $$ = mcopystr("value"); }
| XKWdefault  { $$ = mcopystr("default"); }
| XKWextend   { $$ = mcopystr("extend"); }
| XKWmetainfo { $$ = mcopystr("metainfo"); }
| XKWfor      { $$ = mcopystr("for"); }
| XKWunbound  { $$ = mcopystr("unbound"); }
| XKWnumber   { $$ = mcopystr("number"); }
| XKWstring   { $$ = mcopystr("string"); }
| XKWinteger  { $$ = mcopystr("integer"); }
| XKWarray    { $$ = mcopystr("array"); }
| XKWobject   { $$ = mcopystr("object"); }
| XKWobjectMember { $$ = mcopystr("objectMember"); }
| XKWliteral  { $$ = mcopystr("literal"); }
;

XAsValue:
  XKWas XSpaces XKWvalue { jsonstruct->as_value = true; }
;

XDefault:
  XKWdefault XOptSpaces XJsonValue
  { jsonstruct->default_value.str = $3; jsonstruct->default_value.type = JsonAST::JD_LEGACY; }
;

XExtend:
  XKWextend XOptSpaces XJsonValue XOptSpaces ':' XOptSpaces XJsonValue
  { jsonstruct->schema_extensions.add(new JsonSchemaExtension($3, $7)); }
;

XJsonValue:
  XJsonValueStart XJsonValueCore XJsonValueEnd { $$ = $2; }
| XJsonValueStart XJsonValueEnd                { $$ = mcopystr(""); }
;

XJsonValueCore:
  XJsonValueCore XJsonValueSegment { $$ = mputstr($1, $2); Free($2); }
| XJsonValueSegment                { $$ = $1; }
;

XMetainfoForUnbound:
  XKWmetainfo XOptSpaces XKWfor XOptSpaces XKWunbound { jsonstruct->metainfo_unbound = true; }
;

XAsNumber:
  XKWas XOptSpaces XKWnumber { jsonstruct->as_number = true; }

XTypeIndicator:
  XKWnumber       { jsonstruct->type_indicator = JsonAST::JSON_NUMBER; }
| XKWinteger      { jsonstruct->type_indicator = JsonAST::JSON_INTEGER; }
| XKWstring       { jsonstruct->type_indicator = JsonAST::JSON_STRING; }
| XKWarray        { jsonstruct->type_indicator = JsonAST::JSON_ARRAY; }
| XKWobject       { jsonstruct->type_indicator = JsonAST::JSON_OBJECT; }
| XKWobjectMember { jsonstruct->type_indicator = JsonAST::JSON_OBJECT_MEMBER; }
| XKWliteral      { jsonstruct->type_indicator = JsonAST::JSON_LITERAL; }
;

XOptSpaces:
  /* Empty */
| XSpaces
;

XSpaces:
  XSpaces XSpace
| XSpace
;

XSpace:
  ' '
| '\t'
;


// JSON attributes with no prefix (standard-compliant attributes)
JSONattributes:
  JSONattribute { json_f = true; }
;

JSONattribute:
  JOmitAsNull
/* the name as '...' is handled in the XER attributes section */
| JAsValue
| JDefault
| JExtend
| JMetainfoForUnbound
| JAsNumber
| JChosen
| JAsMap
| JEscapeAs
;

JOmitAsNull:
  XOmitKeyword XKWas XNullKeyword { jsonstruct->omit_as_null = true; }
;

JAsValue:
  XAsValueKeyword { jsonstruct->as_value = true; }
;

JDefault:
  XKWdefault XOptSpaces XJsonValue XOptSpaces
  {
    jsonstruct->default_value.str = $3;
    jsonstruct->default_value.type = JsonAST::JD_STANDARD;
    jsonstruct->default_value.loc = new Common::Location(infile, @3);
  }
;

JExtend:
  XKWextend XOptSpaces XJsonValue XOptSpaces ':' XOptSpaces XJsonValue XOptSpaces
  { jsonstruct->schema_extensions.add(new JsonSchemaExtension($3, $7)); }
;

JMetainfoForUnbound:
  XKWmetainfo XKWfor XKWunbound { jsonstruct->metainfo_unbound = true; }
;

JAsNumber:
  XKWas XKWnumber { jsonstruct->as_number = true; }
;

JChosen:
  XChosenKeyword '(' XAssocList XoptSemiColon ')'
  {
    if (jsonstruct->tag_list == NULL) {
      jsonstruct->tag_list = new rawAST_tag_list;
    }
    else {
      free_rawAST_tag_list(jsonstruct->tag_list);
    }
    link_rawAST_tag_list(jsonstruct->tag_list, &$3);
  }
;

JAsMap:
  XKWas XJsonMap { jsonstruct->as_map = true; }
;

JEscapeAs:
  XKWescape XKWas XKWshort       { jsonstruct->string_escaping = JsonAST::ESCAPE_AS_SHORT; }
| XKWescape XKWas XKWusi         { jsonstruct->string_escaping = JsonAST::ESCAPE_AS_USI; }
| XKWescape XKWas XKWtransparent { jsonstruct->string_escaping = JsonAST::ESCAPE_AS_TRANSPARENT; }
;

%%

/* parse_rawAST(), which calls our rawAST_parse, is over in rawASST.l */

#ifndef NDEBUG
static void yyprint(FILE *file, int type, const YYSTYPE& value)
{
  switch (type) {
  case XIdentifier:
    fprintf(file, "``%s''", value.identifier->get_name().c_str());
    break;
  case Xstring:
    fprintf(file, "``%s''", value.str);
    break;
  default:
    fprintf(file, "# %d", type);
    break;
  }
}
#endif

/*
 Local Variables:
 mode: C
 indent-tabs-mode: nil
 c-basic-offset: 4
 End:
*/
