%{
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2019 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
///////////////////////////////////////////////////////////////////////////////

//
//  File:               SDP_parser.y
//  Rev:                R14C
//  Prodnr:             CNL 113 353
//  Contact:            http://ttcn.ericsson.se
//  Reference:          ITU-T SDP
/*C declarations*/

#include "SDP_parse_parser.h"
#include <stdarg.h>
#define YYDEBUG 1
using namespace SDP__Types;

extern int SDP_parse_lex();
extern int SDP_parse_error(char *s);

SDP__Message* SDP_parse_parsed_message;

SDP__Message* SDP_parse_get_parsed_message() {
	return SDP_parse_parsed_message;
}

void SDP_parse_set_parsed_message(SDP__Message* pdu) {
	SDP_parse_parsed_message=pdu;
}


%}

/*Bison declarations*/

%union {
	int number;
	INTEGER* intnum;
	char byte;
	CHARSTRING* t_charstring;
	SDP__Types::SDP__Message* t_sdp_message;
	SDP__Types::SDP__Origin* t_sdp_origin;
	SDP__Types::SDP__contact* t_sdp_contact;
	SDP__Types::SDP__email__list* t_sdp_email_list;
	SDP__Types::SDP__phone__list* t_sdp_phone_list;
	SDP__Types::SDP__connection* t_sdp_connection;
	SDP__Types::SDP__connection__list* t_sdp_connection_list;
	SDP__Types::SDP__conn__addr* t_sdp_conn_addr;
	SDP__Types::SDP__bandwidth* t_sdp_bandwidth;
	SDP__Types::SDP__time__list* t_sdp_time_list;
	SDP__Types::SDP__time* t_sdp_time;
	SDP__Types::SDP__time__field* t_sdp_time_field;
	SDP__Types::SDP__repeat* t_sdp_repeat;
	SDP__Types::SDP__repeat__list* t_sdp_repeat_list;
	SDP__Types::SDP__timezone__list* t_sdp_timezone_list;
	SDP__Types::SDP__timezone* t_sdp_timezone;
	SDP__Types::SDP__typed__time* t_sdp_typed_time;
	SDP__Types::SDP__typed__time__list* t_sdp_typed_time_list;
	SDP__Types::SDP__key* t_sdp_key;
	SDP__Types::SDP__attribute* t_sdp_attribute;
	SDP__Types::SDP__attribute__list* t_sdp_attribute_list;
	SDP__Types::SDP__media__desc* t_sdp_media_desc;
	SDP__Types::SDP__media__desc__list* t_sdp_media_desc_list;
	SDP__Types::SDP__media__field* t_sdp_media_field;
	SDP__Types::SDP__fmt__list* t_sdp_fmt_list;
	SDP__Types::SDP__bandwidth__list* t_bandwidth_list;
	SDP__Types::SDP__url__list* t_url_list;
	SDP__Types::SDP__media__type__list* t_type_list;
	SDP__Types::SDP__id__tag__list* t_id_list;
	SDP__Types::SDP__Remote__candidate__list* t_candidate_list;	
	SDP__Types::SDP__Remote__candidate* t_candidate;	
	SDP__Types::SDP__extension__list* t_extension_list;	
	SDP__Types::SDP__extension* t_extension;
	SDP__Types::SDP__ice__options__list* t_sdp_ice_option_list;		
}

%type <t_sdp_message> announcement
%type <t_bandwidth_list> bandwidth_list
%type <t_sdp_media_desc_list> media_descriptions
%type <t_url_list> url_list
%type <t_id_list> id_list
%type <t_type_list> type_list
%type <t_sdp_fmt_list> fmt_list

%type <t_sdp_media_field> media_field

%type <t_sdp_media_desc> media_description

%type <t_sdp_attribute_list> attribute_fields
%type <t_sdp_attribute> attribute_field attribute
%type <t_sdp_key> key_field key_type

%type <t_sdp_time_list> time_list
%type <t_sdp_time> time
%type <t_sdp_time_field> time_field
%type <t_sdp_repeat> repeat
%type <t_sdp_repeat_list> repeat_list
%type <t_sdp_timezone_list> timezone_list timezones_field
%type <t_sdp_timezone> timezone
%type <t_sdp_typed_time> typed_time
%type <t_sdp_typed_time_list> offsets

%type <t_sdp_origin> origin_field 
%type <t_charstring>  session_name_field information_field uri_field email_text phone transport

%type <t_candidate_list> candidate_list
%type <t_candidate> candidate
%type <t_extension_list> extension_list
%type <t_extension> extension
%type <t_sdp_ice_option_list> ice_option_list

%type <t_sdp_email_list> email_fields

%type <t_sdp_phone_list> phone_fields

%type <t_sdp_contact> email_field email_address phone_field phone_number

%type <t_sdp_connection> connection_field connection_field_lonely

%type <t_sdp_connection_list> connection_fields

%type <t_sdp_conn_addr> conn_address

%type <t_sdp_bandwidth> bandwidth_field

%type <number> pos_digit digit  proto_version

%type <byte>  alpha_numeric email_byte 

%token <number> _ZERO _ONE _TWO _THREE _FOUR _FIVE _SIX _SEVEN _EIGHT _NINE

%token CRLF

%token <byte> ALPHA SPACE UNDERSCORE PERIOD ANYBYTE LBRACE RBRACE LT GT PLUS HYPHEN SLASH COLON

%token <t_charstring> EMAIL TOKEN
%type  <t_charstring> rel_addr rel_port

%token <intnum> INTTOKEN

%token VEQ OEQ SEQ IEQ UEQ EEQ PEQ CEQ BEQ BW_CT BW_AS TEQ ZEQ REQ KEQ AEQ MEQ

%token A_CAT A_KEYWDS A_TOOL A_PTIME A_RECVONLY A_SENDRECV A_SENDONLY A_ORIENT A_TYPE A_CHARSET A_SDLANG
%token A_LANG A_FRAMERATE A_QUALITY A_FMTP A_CURR A_DES A_CONF A_RTMAP A_RTCP A_MAX_SIZE A_PATH A_ACCEPT_TYPES
%token A_ACCEPT_WRAPPED_TYPES A_MAXPRATE A_MID A_GROUP A_FILE_SELECTOR A_FILE_TRANSFER_ID A_INACTIVE A_SETUP
%token A_CONNECTION A_CRYPTO A_CONTENT A_LABEL A_FLOORCTRL A_CONFID A_USERID A_FLOORID A_FINGERPRINT
%token A_ICE_UFRAG A_ICE_PWD A_CANDIDATE A_ICE_LITE A_ICE_MISMATCH A_REMOTE_CANDIDATE A_ICE_OPTIONS
%token A_RTCP_FB A_MAXPTIME

%token A_T38_VERSION A_T38_BITRATE A_T38_BITREMOVAL A_T38_MMR A_T38_JBIG A_T38_RATEMANAGEMENT
%token A_T38_MAXBUFFER A_T38_MAXDATAGRAM A_T38_IFP A_T38_EC A_T38_ECDEPTH A_T38_FEC A_T38_VENDORINFO
%token A_T38_MODEM 

%token A_FILE_DISPOSITION A_FILE_DATE A_FILE_ICON A_FILE_RANGE
%token A_SCTPMAP A_SCTPPORT A_MAX_MSG_SIZE A_RTCP_MUX
%start announcement

%%

/*Grammar rules*/

announcement: 	proto_version 
				origin_field
				session_name_field
				information_field
				uri_field
				email_fields
				phone_fields
				connection_field_lonely
				bandwidth_list
				time_list
				timezones_field
				key_field
				attribute_fields
				media_descriptions
				{
//				SDP_parse_parsed_message = new SDP__Message;
				(*SDP_parse_parsed_message).protocol__version() = $1;
				(*SDP_parse_parsed_message).origin() = *$2;
				delete $2;
				(*SDP_parse_parsed_message).session__name() = *$3;
				delete $3;

				if ($4 != NULL) { // information field present
					(*SDP_parse_parsed_message).information() = *$4;
					delete $4;
				} else
					(*SDP_parse_parsed_message).information() = OMIT_VALUE;

				if ($5 != NULL) { // uri field present
					(*SDP_parse_parsed_message).uri() = *$5;
					delete $5;
				} else
					(*SDP_parse_parsed_message).uri() = OMIT_VALUE;
				if ($6 != NULL) { //email fields present
					(*SDP_parse_parsed_message).emails() = *$6;
					delete $6;
				} else
					(*SDP_parse_parsed_message).emails() = OMIT_VALUE;
				if ($7 != NULL) { // phone fields present
					(*SDP_parse_parsed_message).phone__numbers() = *$7;
					delete $7;
				} else
					(*SDP_parse_parsed_message).phone__numbers() = OMIT_VALUE;
				
				
				if ($8 != NULL) { // connection fields present
				(*SDP_parse_parsed_message).connection() = (*$8);
				delete $8;
				} else 
				  (*SDP_parse_parsed_message).connection() = OMIT_VALUE;
				  
				if ($9 != NULL) {
					(*SDP_parse_parsed_message).bandwidth() = *$9;
					delete $9;
				} else
					(*SDP_parse_parsed_message).bandwidth() = OMIT_VALUE;

				(*SDP_parse_parsed_message).times() = *$10;
					delete $10;

				if ($11 != NULL) {
					(*SDP_parse_parsed_message).timezone__adjustments() = *$11;
					delete $11;
				} else
					(*SDP_parse_parsed_message).timezone__adjustments() = OMIT_VALUE;

				
				if ($12 != NULL) {
					(*SDP_parse_parsed_message).key () = *$12;
					delete $12;
				} else {
					(*SDP_parse_parsed_message).key() = OMIT_VALUE;
				}
				
				if ($13 != NULL) {
					(*SDP_parse_parsed_message).attributes() = *$13;
					delete $13;
				} else {
					(*SDP_parse_parsed_message).attributes() = OMIT_VALUE;
				}
				if ($14 != NULL) {
					(*SDP_parse_parsed_message).media__list() = *$14;
					delete $14;
				} else 
					(*SDP_parse_parsed_message).media__list() = OMIT_VALUE;
				
				YYACCEPT;
			  }

media_descriptions: /*empty*/ {$$ = NULL;}
					| media_descriptions media_description {
						if ($1 != NULL) {
							int media_num = (*$1).size_of();
							(*$1)[media_num] = *$2;
							delete $2;
						} else {
							$$ = new SDP__media__desc__list();
							(*$$)[0] = *$2;
							delete $2;
						}
					}

media_description: 	media_field
					information_field
					connection_fields
					bandwidth_list
					key_field
					attribute_fields
					{
						$$ = new SDP__media__desc();
						(*$$).media__field() = *$1;
						delete $1;
						if ($2 != NULL) {
							(*$$).information() = *$2;
							delete $2;
						} else
							(*$$).information() = OMIT_VALUE;
						if ($3 != NULL) {
							(*$$).connections() = *$3;
							delete $3;
						} else 
							(*$$).connections() = OMIT_VALUE;
						if ($4 != NULL) {
							(*$$).bandwidth() = *$4;
							delete $4;
						} else
							(*$$).bandwidth() = OMIT_VALUE;
						if ($5 != NULL) {
							(*$$).key() = *$5;
							delete $5;
						} else
							(*$$).key() = OMIT_VALUE;
						if ($6 != NULL) {
							(*$$).attributes() = *$6;
							delete $6;
						} else
							(*$$).attributes()=  OMIT_VALUE;
					}

media_field:		MEQ TOKEN SPACE TOKEN SLASH TOKEN
					SPACE transport SPACE fmt_list CRLF {
						$$ = new SDP__media__field();
						(*$$).media() = *$2;
						delete $2;
						(*$$).ports().port__number() = str2int(*$4);
						delete $4;
						(*$$).ports().num__of__ports() = str2int(*$6);
						delete $6;
						(*$$).transport() = *$8;
						delete $8;
						(*$$).fmts() = *$10;
						delete $10;
					}
					| MEQ TOKEN SPACE TOKEN
					SPACE transport SPACE fmt_list CRLF {
						$$ = new SDP__media__field();
						(*$$).media() = *$2;
						delete $2;
						(*$$).ports().port__number() = str2int(*$4);
						delete $4;
						(*$$).ports().num__of__ports() = OMIT_VALUE;
						(*$$).transport() = *$6;
						delete $6;
						(*$$).fmts() = *$8;
						delete $8;
					}

transport: TOKEN { $$=$1;}
       | transport SLASH TOKEN {
         const CHARSTRING& str = *$1+CHARSTRING(1,"/")+*$3;
         delete $1;
         delete $3;
         $$ = new CHARSTRING(str);
         
       }

fmt_list:	TOKEN {
				$$ = new SDP__fmt__list();
				(*$$)[0] = *$1;
				delete $1;
			}
			| fmt_list SPACE TOKEN {
				int fmt_num = (*$1).size_of();
				(*$1)[fmt_num] = *$3;
				delete $3;
				$$ = $1;
			}

attribute_fields:  	/*empty*/ {
						$$ = NULL;
					}
					| attribute_fields attribute_field {
						if ($1 != NULL) {
							int att_num = (*$1).size_of();
							(*$1)[att_num] = *$2;
							delete $2;
						} else {
							$$ = new SDP__attribute__list();
							(*$$)[0] = *$2;
							delete $2;
						}
					}
					

attribute_field:	AEQ attribute CRLF {
						$$ = $2;
					}

attribute:		A_CAT TOKEN {
					$$ = new SDP__attribute();
					(*$$).cat().attr__value() = *$2;
					delete $2;
				}
				| A_KEYWDS TOKEN {
					$$ = new SDP__attribute();
					(*$$).keywds().attr__value() = *$2;
					delete $2;
				}
				| A_TOOL TOKEN {
					$$ = new SDP__attribute();
					(*$$).tool().attr__value() = *$2;
					delete $2;
				}
				| A_PTIME TOKEN {
					$$ = new SDP__attribute();
					(*$$).ptime().attr__value() = *$2;
					delete $2;
				}
				| A_RECVONLY {
					$$ = new SDP__attribute();
					(*$$).recvonly() = SDP__attribute__recvonly(NULL_VALUE);
				}
				| A_SENDRECV {
					$$ = new SDP__attribute();
					(*$$).sendrecv() = SDP__attribute__sendrecv(NULL_VALUE);
				}
				| A_SENDONLY {
					$$ = new SDP__attribute();
					(*$$).sendonly() = SDP__attribute__sendonly(NULL_VALUE);
				}
				| A_ORIENT TOKEN {
					$$ = new SDP__attribute();
					(*$$).orient().attr__value() = *$2;
					delete $2;
				}
				| A_TYPE TOKEN {
					$$ = new SDP__attribute();
					(*$$).sdp__type().attr__value() = *$2;
					delete $2;
				}
				| A_CHARSET TOKEN {
					$$ = new SDP__attribute();
					(*$$).charset().attr__value() = *$2;
					delete $2;
				}
				| A_SDLANG TOKEN {
					$$ = new SDP__attribute();
					(*$$).sdplang().attr__value() = *$2;
					delete $2;
				}
				| A_LANG TOKEN {
					$$ = new SDP__attribute();
					(*$$).lang().attr__value() = *$2;
					delete $2;
				}
				| A_FRAMERATE TOKEN {
					$$ = new SDP__attribute();
					(*$$).framerate().attr__value() = *$2;
					delete $2;
				}
				| A_QUALITY TOKEN {
					$$ = new SDP__attribute();
					(*$$).quality().attr__value() = *$2;
					delete $2;
				}
				| A_FMTP TOKEN {
					$$ = new SDP__attribute();
					(*$$).fmtp().attr__value() = *$2;
					delete $2;
				}
				| A_CURR TOKEN {
					$$ = new SDP__attribute();
					(*$$).curr().attr__value() = *$2;
					delete $2;
				}
				| A_DES TOKEN {
					$$ = new SDP__attribute();
					(*$$).des().attr__value() = *$2;
					delete $2;
				}
				| A_CONF TOKEN {
					$$ = new SDP__attribute();
					(*$$).conf().attr__value() = *$2;
					delete $2;
				}
				| A_RTMAP TOKEN {
					$$ = new SDP__attribute();
					(*$$).rtpmap().attr__value() = *$2;
					delete $2;
				}
				| A_RTCP TOKEN {
					$$ = new SDP__attribute();
					(*$$).rtcp().attr__value() = *$2;
					delete $2;
				}
				| A_MAX_SIZE TOKEN {
					$$ = new SDP__attribute();
					(*$$).max__size().max__size() = str2int(*$2);
					delete $2;
				}
				| A_PATH url_list {
					$$ = new SDP__attribute();
					(*$$).path().path__list() = *$2;
					delete $2;
				}
				| A_ACCEPT_TYPES type_list {
					$$ = new SDP__attribute();
					(*$$).accept__types().attr__value() = *$2;
					delete $2;
				}
				| A_ACCEPT_WRAPPED_TYPES type_list {
					$$ = new SDP__attribute();
					(*$$).accept__wrapped__types().attr__value() = *$2;
					delete $2;
				}
				| A_MAXPRATE TOKEN {
					$$ = new SDP__attribute();
					(*$$).maxprate().prate__integer__part() = str2int(*$2);
					(*$$).maxprate().prate__fraction__part() = OMIT_VALUE;
					delete $2;
				}
				| A_MAXPRATE TOKEN PERIOD TOKEN{
					$$ = new SDP__attribute();
					(*$$).maxprate().prate__integer__part() = str2int(*$2);
					(*$$).maxprate().prate__fraction__part() = str2int(*$4);
					delete $2;
					delete $4;
				}
				| A_MID TOKEN {
					$$ = new SDP__attribute();
					(*$$).mid().id__tag() = *$2;
					delete $2;
				}
				| A_GROUP TOKEN {
					$$ = new SDP__attribute();
					(*$$).group__attr().semantics() = *$2;
					(*$$).group__attr().id__tag()=OMIT_VALUE;
					delete $2;
				}
				| A_GROUP TOKEN SPACE id_list{
					$$ = new SDP__attribute();
					(*$$).group__attr().semantics() = *$2;
					(*$$).group__attr().id__tag()=*$4;
					delete $2;
					delete $4;
				}
				| A_FILE_SELECTOR TOKEN {
					$$ = new SDP__attribute();
					(*$$).file__selector().attr__value() = *$2;
					delete $2;
				}
				| A_FILE_TRANSFER_ID TOKEN {
					$$ = new SDP__attribute();
					(*$$).file__transfer__id().attr__value() = *$2;
					delete $2;
				}
				| A_INACTIVE{
					$$ = new SDP__attribute();
					(*$$).inactive() = SDP__attribute__inactive(NULL_VALUE);
				}
				| A_RTCP_MUX{
					$$ = new SDP__attribute();
					(*$$).rtcp__mux() = SDP__attribute__rtcp__mux(NULL_VALUE);
				}
				| A_SETUP TOKEN {
					$$ = new SDP__attribute();
					(*$$).setup().attr__value() = *$2;
					delete $2;
				}
				| A_CONNECTION TOKEN {
					$$ = new SDP__attribute();
					(*$$).connection().attr__value() = *$2;
					delete $2;
				}
				| A_CRYPTO TOKEN {
					$$ = new SDP__attribute();
					(*$$).crypto().attr__value() = *$2;
					delete $2;
				}
				| A_CONTENT TOKEN {
					$$ = new SDP__attribute();
					(*$$).content().attr__value() = *$2;
					delete $2;
				}
				| A_LABEL TOKEN {
					$$ = new SDP__attribute();
					(*$$).attr__label().attr__value() = *$2;
					delete $2;
				}
				| A_FLOORCTRL TOKEN {
					$$ = new SDP__attribute();
					(*$$).floorctrl().attr__value() = *$2;
					delete $2;
				}
				| A_CONFID TOKEN {
					$$ = new SDP__attribute();
					(*$$).confid().attr__value() = *$2;
					delete $2;
				}
				| A_USERID TOKEN {
					$$ = new SDP__attribute();
					(*$$).userid().attr__value() = *$2;
					delete $2;
				}
				| A_FLOORID TOKEN {
					$$ = new SDP__attribute();
					(*$$).floorid().attr__value() = *$2;
					delete $2;
				}
				| A_FINGERPRINT TOKEN {
					$$ = new SDP__attribute();
					(*$$).fingerprint().attr__value() = *$2;
					delete $2;
				}
				| A_ICE_UFRAG TOKEN {
				        $$ = new SDP__attribute();
				        (*$$).ice__ufrag().attr__value() = *$2;
					delete $2;
				}
				| A_ICE_PWD TOKEN {
				        $$ = new SDP__attribute();
				        (*$$).ice__pwd().attr__value() = *$2;
					delete $2;
				}
				| A_CANDIDATE TOKEN SPACE TOKEN SPACE TOKEN
				   SPACE TOKEN SPACE TOKEN SPACE TOKEN SPACE TOKEN
				       SPACE TOKEN rel_addr rel_port extension_list{
				        $$ = new SDP__attribute();
				        (*$$).candidate().foundation() = *$2; 
				        delete $2;
			                (*$$).candidate().component__id() = str2int(*$4);
			                delete $4;
			                (*$$).candidate().transport() = *$6; 
			                delete $6;
			                (*$$).candidate().priority() = str2int(*$8);
				        delete $8;
					(*$$).candidate().connection__address() = *$10;  
				        delete $10;
					(*$$).candidate().connection__port() = str2int(*$12); 
					delete $12;					  
					delete $14;
					(*$$).candidate().candidate__type() = *$16;  
					delete $16;					
					if ($17 != NULL) {
							(*$$).candidate().rel__address() = *$17;
							delete $17;
						} else
							(*$$).candidate().rel__address() = OMIT_VALUE;
                                        if ($18 != NULL) {
							(*$$).candidate().rel__port() = *$18;
							delete $18;
						} else
							(*$$).candidate().rel__port() = OMIT_VALUE;					
				
				        if ($19 != NULL) {
							(*$$).candidate().extensions() = *$19;
							delete $19;
						} else
							(*$$).candidate().extensions() = OMIT_VALUE;	
				}																
				| A_ICE_LITE {
					$$ = new SDP__attribute();
					(*$$).ice__lite() = SDP__attribute__ice__lite(NULL_VALUE);
				}																
				| A_ICE_MISMATCH {
					$$ = new SDP__attribute();
					(*$$).ice__mismatch() = SDP__attribute__ice__mismatch(NULL_VALUE);
				}
				| A_REMOTE_CANDIDATE candidate_list
				{   
				        $$ = new SDP__attribute();
                                        (*$$).remote__candidate().attr__value() = *$2;
                                        delete $2;
                                }
				| A_ICE_OPTIONS ice_option_list {
					$$ = new SDP__attribute();
					(*$$).ice__options().attr__value() = *$2;
					delete $2;
				}				
                                | A_RTCP_FB TOKEN {
				        $$ = new SDP__attribute();
				        (*$$).rtcp__fb().attr__value() = *$2;
					delete $2;
				}				
                                | A_MAXPTIME TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).maxptime().attr__value() = *$2;				
					delete $2;
				}
                                | A_T38_VERSION TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__version().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_BITRATE TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__bit__rate().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_BITREMOVAL TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__fill__bit__removal().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_MMR TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__transcoding__mmr().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_JBIG TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__transcoding__jbig().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_RATEMANAGEMENT TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__rate__management().attr__value() = *$2;				
					delete $2;
				}
                                | A_T38_MAXBUFFER TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__max__buffer().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_MAXDATAGRAM TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__max__datagram().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_IFP TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__max__ifp().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_EC TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__udp__ec().attr__value() = *$2;				
					delete $2;
				}
                                | A_T38_ECDEPTH TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__udp__ec__depth().minred() = str2int(*$2);
                                        (*$$).t38__udp__ec__depth().maxred() = OMIT_VALUE;				
					delete $2;
				}
                                | A_T38_ECDEPTH TOKEN SPACE TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__udp__ec__depth().minred() = str2int(*$2);
                                        (*$$).t38__udp__ec__depth().maxred() = str2int(*$4);				
					delete $2;
                                        delete $4;
				}
                                | A_T38_FEC TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__udp__fec__max__spam().attr__value() = str2int(*$2);				
					delete $2;
				}
                                | A_T38_VENDORINFO TOKEN SPACE TOKEN SPACE TOKEN {				
				        $$ = new SDP__attribute();				
                                        (*$$).t38__vendor__info().t35country__code() = str2int(*$2);
                                        (*$$).t38__vendor__info().t35extension() = str2int(*$4);
                                        (*$$).t38__vendor__info().manufacturer__code() = str2int(*$6);				
                                        delete $2;
                                        delete $4;				
					delete $6;
				}
                                | A_T38_MODEM TOKEN {				
				        $$ = new SDP__attribute();				
				        (*$$).t38__modem__type().attr__value() = *$2;				
					delete $2;
				} 																												
				| A_FILE_DISPOSITION TOKEN {
					$$ = new SDP__attribute();
					(*$$).file__disposition().attr__value() = *$2;
					delete $2;
				}				
				| A_FILE_DATE TOKEN {
					$$ = new SDP__attribute();
					(*$$).file__date().attr__value() = *$2;
					delete $2;
				}				
				| A_FILE_ICON TOKEN {
					$$ = new SDP__attribute();
					(*$$).file__icon().attr__value() = *$2;
					delete $2;
				}				
				| A_FILE_RANGE TOKEN {
					$$ = new SDP__attribute();
					(*$$).file__range().attr__value() = *$2;
					delete $2;
				}				
        | A_SCTPMAP TOKEN {
					$$ = new SDP__attribute();
					(*$$).sctpmap().attr__value() = *$2;
					delete $2;
				}				
        | A_SCTPPORT TOKEN {
					$$ = new SDP__attribute();
					(*$$).sctp__port().attr__value() = str2int(*$2);
					delete $2;
				}				
        | A_MAX_MSG_SIZE TOKEN {
					$$ = new SDP__attribute();
					(*$$).max__message__size().attr__value() = str2int(*$2);
					delete $2;
				}				

				| TOKEN COLON TOKEN {
					$$ = new SDP__attribute();
					(*$$).unknown().name() = *$1;
					delete $1;
					(*$$).unknown().attr__value() = *$3;
					delete $3;
                                }
				| TOKEN {
					$$ = new SDP__attribute();
					(*$$).unknown().name() = *$1;
					delete $1;
					(*$$).unknown().attr__value() = OMIT_VALUE;
				}									
							
ice_option_list:	 	TOKEN {
					$$ = new SDP__ice__options__list();
					(*$$)[0] = *$1;
					delete $1;
				}
				| ice_option_list SPACE TOKEN {
					int ice_option_num = (*$1).size_of();
					(*$1)[ice_option_num] = *$3;
					delete $3;
					$$ = $1;
				}
															
candidate_list:	               candidate {
					$$ = new SDP__Remote__candidate__list();
					(*$$)[0] = *$1;
					delete $1;
				}           				
				| candidate_list SPACE candidate {
					int candidate_num = (*$1).size_of();
					(*$1)[candidate_num] = *$3;
					delete $3;
					$$ = $1;
				}
											
candidate:               TOKEN SPACE TOKEN SPACE TOKEN{
						$$ = new SDP__Remote__candidate();
						(*$$).component__Id() = *$1;
						delete $1;
						(*$$).connection__address() = *$3;
						delete $3;
					        (*$$).portValue() = str2int(*$5);
						delete $5;							
					}
  													
rel_addr:               /*empty*/ {$$ = NULL;}
                            | SPACE TOKEN SPACE TOKEN{
			      delete $2;
	                      $$ = $4;			     
			}


rel_port:               /*empty*/ {$$ = NULL;}
                            | SPACE TOKEN SPACE TOKEN{
			      delete $2;
	                      $$ = $4;
			}

extension_list:          /*empty*/ {$$ = NULL;}
                         | extension_list extension {
			 if ($1 != NULL) {
						int extension_num = (*$1).size_of();
						(*$1)[extension_num] = *$2;
						delete $2;
						$$ = $1;
					} else {
						$$ = new SDP__extension__list();
						(*$$)[0] = *$2;
						delete $2;
					}
				}
								 
extension:               SPACE TOKEN SPACE TOKEN {
						$$ = new SDP__extension();
						(*$$).extension__attr__name() = *$2;
						delete $2;
						(*$$).extension__attr__value() = *$4;
						delete $4;
					}


url_list:	 	TOKEN {
					$$ = new SDP__url__list();
					(*$$)[0] = *$1;
					delete $1;
				}
				| url_list SPACE TOKEN {
					int url_num = (*$1).size_of();
					(*$1)[url_num] = *$3;
					delete $3;
					$$ = $1;
				}

id_list:	 	TOKEN {
					$$ = new SDP__id__tag__list();
					(*$$)[0] = *$1;
					delete $1;
				}
				| id_list SPACE TOKEN {
					int id_num = (*$1).size_of();
					(*$1)[id_num] = *$3;
					delete $3;
					$$ = $1;
				}

type_list:	 	TOKEN {
					$$ = new SDP__media__type__list();
					(*$$)[0] = *$1;
					delete $1;
				}
				| type_list SPACE TOKEN {
					int url_num = (*$1).size_of();
					(*$1)[url_num] = *$3;
					delete $3;
					$$ = $1;
				}


key_field:	/*empty*/ {$$ = NULL;}
			| KEQ key_type CRLF {
				$$ = $2;
				
			}

key_type:	TOKEN {
				$$ = new SDP__key();
				(*$$).method() = *$1;
				delete $1;
				(*$$).key() = OMIT_VALUE;
			}
			| TOKEN COLON TOKEN {
				$$ = new SDP__key();
				(*$$).method() = *$1;
				delete $1;
				(*$$).key() = *$3;
				delete $3;
			}



time_list:	 	time {
					$$ = new SDP__time__list();
					(*$$)[0] = *$1;
					delete $1;
				}
				| time_list time {
					int time_num = (*$1).size_of();
					(*$1)[time_num] = *$2;
					delete $2;
					$$ = $1;
				}

time:		time_field repeat_list{
				$$ = new SDP__time;
				(*$$).time__field() = *$1;
				delete $1;
				if ($2 != NULL) {
					(*$$).time__repeat() = *$2;
					delete $2;
				} else
					(*$$).time__repeat() = OMIT_VALUE;
			}

repeat_list:	/*empty*/ {$$ = NULL;}
				| repeat_list repeat {
					if ($1 != NULL) {
						int repeat_num = (*$1).size_of();
						(*$1)[repeat_num] = *$2;
						delete $2;
						$$ = $1;
					} else {
						$$ = new SDP__repeat__list();
						(*$$)[0] = *$2;
						delete $2;
					}
				}
					

repeat:		REQ typed_time SPACE typed_time SPACE offsets CRLF {
				$$ = new SDP__repeat();
				(*$$).repeat__interval() = *$2;
				delete $2;
				(*$$).active() = *$4;
				delete $4;
				(*$$).offsets() = *$6;
				delete $6;
			}


offsets:	typed_time {
				$$ = new SDP__typed__time__list();
				(*$$)[0] = *$1;
				delete $1;
			}
			| offsets SPACE typed_time {
				int off_size = (*$1).size_of();
				(*$$)[off_size] = *$3;
				delete $3;
			}

timezones_field:	/*empty*/ {$$ = NULL;}
				| ZEQ timezone_list CRLF {
					$$ = $2;
				}

timezone_list:	timezone {
					$$ = new SDP__timezone__list();
					(*$$)[0] = *$1;
					delete $1;
				}
				| timezone_list SPACE timezone {
					int tz_num = (*$1).size_of();
					(*$1)[tz_num] = *$3;
					delete $3;
					$$ = $1;
				}

timezone:		INTTOKEN SPACE typed_time {
					$$ = new SDP__timezone();
					(*$$).adjustment__time() = int2str(*$1);
					delete $1;
					(*$$).offset() = *$3;
					delete $3;
				}

typed_time:		INTTOKEN {
					$$ = new SDP__typed__time();
					(*$$).time() = *$1;
					delete $1;
					(*$$).unit() = OMIT_VALUE;
				}
				| INTTOKEN ALPHA {
					$$ = new SDP__typed__time();
					(*$$).time() = *$1;
					delete $1;
					(*$$).unit() = CHARSTRING(1, (const char*)&$2);
				}

time_field:		TEQ TOKEN SPACE TOKEN CRLF { // start_time SPACE stop_time
					$$ = new SDP__time__field();
					(*$$).start__time() = (*$2);
					delete $2;
					(*$$).stop__time() = (*$4);
					delete $4;
				}

bandwidth_list:	/*empty*/ {$$ = NULL;}
				| bandwidth_list bandwidth_field {
					if ($1 != NULL) {
						int bandwidth_num = (*$1).size_of();
						(*$1)[bandwidth_num] = *$2;
						delete $2;
						$$ = $1;
					} else {
						$$ = new SDP__bandwidth__list();
						(*$$)[0] = *$2;
						delete $2;
					}
				}


bandwidth_field:	BEQ TOKEN COLON TOKEN CRLF {
						$$ = new SDP__bandwidth();
						(*$$).modifier() = *$2;
						delete $2;
						(*$$).bandwidth() = str2int(*$4);
						delete $4;
					}


connection_fields: 	/*empty*/ {$$ = NULL;}
					| connection_fields connection_field {
						if ($1 != NULL) {
							int con_num = (*$1).size_of();
							(*$1)[con_num] = *$2;
							delete $2;
							$$ = $1;
						} else {
							$$ = new SDP__connection__list();
							(*$$)[0] = *$2;
							delete $2;
						}
					}


connection_field_lonely: 	 	/*empty*/ {$$ = NULL;}
					| CEQ TOKEN SPACE TOKEN SPACE conn_address CRLF {
						$$ = new SDP__connection();
						(*$$).net__type() = *$2;
						delete $2;
						(*$$).addr__type() = *$4;
						delete $4;
						(*$$).conn__addr() = (*$6);
						delete $6;
					}


connection_field: 	CEQ TOKEN SPACE TOKEN SPACE conn_address CRLF {
						$$ = new SDP__connection();
						(*$$).net__type() = *$2;
						delete $2;
						(*$$).addr__type() = *$4;
						delete $4;
						(*$$).conn__addr() = (*$6);
						delete $6;
					}
conn_address:	TOKEN {
					$$ = new SDP__conn__addr();
					(*$$).addr() = (*$1);
					delete $1;
					(*$$).ttl() = OMIT_VALUE;
					(*$$).num__of__addr() = OMIT_VALUE;
				}
				| TOKEN SLASH TOKEN {
					$$ = new SDP__conn__addr();
					(*$$).addr() = (*$1);
					delete $1;
					(*$$).ttl() = str2int(*$3);
					(*$$).num__of__addr() = OMIT_VALUE;
					delete $3;
				}
				| TOKEN SLASH TOKEN SLASH TOKEN {
					$$ = new SDP__conn__addr();
					(*$$).addr() = (*$1);
					delete $1;
					(*$$).ttl() = str2int(*$3);
					(*$$).num__of__addr() = str2int(*$5);
					delete $3;
					delete $5;
				}


phone_fields: 	/*empty*/ {$$ = NULL;}
				| phone_fields phone_field {
					if ($$ == NULL) {
						$$ = new SDP__phone__list();
						(*$$)[0] = *$2;
						delete $2;
					} else {
						int num_of_phonenumbers = (*$1).size_of();
						(*$1)[num_of_phonenumbers]  =*$2;
						delete $2;
					}
				}

phone_field:	PEQ phone_number CRLF {
					$$ = $2;
				}

phone_number:	phone {
					$$ = new SDP__contact();
					(*$$).addr__or__phone() = (*$1);
					delete $1;
					(*$$).disp__name() = OMIT_VALUE;
				}
				| phone LBRACE email_text RBRACE {
					$$ = new SDP__contact();
					(*$$).addr__or__phone() = *$1;
					delete $1;
					(*$$).disp__name() = *$3;
					delete $3;
				}

				| phone LT phone GT {
					/* phone is any charstring, but with trailing space removed*/
					$$ = new SDP__contact();
					(*$$).addr__or__phone() = *$3;
					delete $3;
					(*$$).disp__name() = *$1;
					delete $1;
				}

phone:	email_text {
			/* remove trailing space, if any */
/* This is a rather ugly post-processing, but otherwise SDP can not
be parsed with an LR(1) parser. Reason: phone number may contain spaces, 
and delimiter between the phone number and the rest of the phone field may be a space*/

			int size = (*$1).lengthof();
			
			const char* buf = (const char*)(*$1);
			
			if (buf[size-1] == ' ') {
				$$ = new CHARSTRING(size-1, (const char*)(*$1));
				delete $1;
			} else
				$$ = $1;
		}

email_fields: 	/*empty*/ {$$ = NULL;}
				| email_fields email_field {
					if ($1 == NULL) {
						$$ = new SDP__email__list();
						(*$$)[0] = *$2;
						delete $2;
					} else {
						int num_of_emails = (*$1).size_of();
						// indexing begins with 0
						(*$1)[num_of_emails] = *$2;
						delete $2;
					}
				}

email_field:	EEQ email_address CRLF {
					$$ = $2;
				}

email_address:	EMAIL {
					$$ = new SDP__contact();
					(*$$).addr__or__phone() = *$1;
					delete $1;
					(*$$).disp__name() = OMIT_VALUE;
				}
				
				| EMAIL SPACE LBRACE email_text RBRACE {
					$$ = new SDP__contact();
					(*$$).addr__or__phone() = *$1;
					delete $1;
					(*$$).disp__name() = *$4;
					delete $4;
				} 
				| email_text SPACE LT EMAIL GT {
					$$ = new SDP__contact();
					(*$$).addr__or__phone() = *$4;
					delete $4;
					(*$$).disp__name() = *$1;
					delete $1;
				} 
				| LT EMAIL GT {
					$$ = new SDP__contact();
					(*$$).addr__or__phone() = *$2;
					delete $2;
					(*$$).disp__name() = OMIT_VALUE;
				} 
				 



uri_field:	/*empty*/ {$$ = NULL;}
			| UEQ TOKEN CRLF {
				$$ = $2;
			}


information_field:	/*empty*/ {$$ = NULL;}
					| IEQ TOKEN CRLF {
						$$ = $2;
					}

session_name_field:	SEQ TOKEN CRLF {
						$$ = $2;
				 }

proto_version: VEQ INTTOKEN CRLF {$$ = *$2; delete $2;}

origin_field:	OEQ TOKEN SPACE TOKEN SPACE TOKEN SPACE
				TOKEN SPACE TOKEN SPACE TOKEN CRLF {
					$$ = new SDP__Origin();
					(*$$).user__name() = *$2;
					delete $2;
					(*$$).session__id() = *$4;
					delete $4;
					(*$$).session__version() = *$6;
					delete $6;
					(*$$).net__type() = *$8;
					delete $8;
					(*$$).addr__type() = *$10;
					delete $10;
					(*$$).addr() = *$12;
					delete $12;
				}






email_text:	email_byte {$$ = new CHARSTRING(1, (const char*)&$1);}
			| email_text email_byte {
				const CHARSTRING& str = *$1 + CHARSTRING(1, (const char*)&$2);
				delete $1;
				$$ = new CHARSTRING(str);
			}




alpha_numeric:	ALPHA {$$ = $1;}
				| digit {$$ = $1 + 0x30;}


digit:		_ZERO {$$ = 0;}
			| pos_digit {$$ = $1;}

pos_digit: 	_ONE {$$ = 1;}
			| _TWO {$$ = 2;}
			| _THREE {$$ = 3;}
			| _FOUR {$$ = 4;}
			| _FIVE {$$ = 5;}
			| _SIX {$$ = 6;}
			| _SEVEN {$$ = 7;}
			| _EIGHT {$$ = 8;}
			| _NINE {$$ = 9;}



email_byte:	alpha_numeric {$$ = $1;}
					| UNDERSCORE {$$ = $1;}
					| PERIOD {$$ = $1;}
					| HYPHEN {$$ = $1;}
					| PLUS {$$ = $1;}
					| SLASH {$$ = $1;}
					| COLON {$$ = $1;}
					| ANYBYTE {$$ = $1;}
					| SPACE {$$ = $1;}

%%

/*Additional C code*/
