diff -r 000000000000 -r 044383f39525 bintools/rcomp/src/RCOMP.YACC --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bintools/rcomp/src/RCOMP.YACC Tue Oct 27 16:36:35 2009 +0000 @@ -0,0 +1,1295 @@ +%{ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// RCOMP.CPP +// Generated from RCOMP.Y + +#include +#include +#include + +#if defined(__MSVCDOTNET__) || defined(__TOOLS2__) +#include +#include +using namespace std; +using std::cout; +using std::endl; +#else //!__MSVCDOTNET__ +#include +#endif //__MSVCDOTNET__ + +#ifdef __VC32__ +#pragma warning( disable : 4065 ) // C4065: switch statement contains 'default' but no 'case' labels +#pragma warning( disable : 4102 ) // C4102: 'yyerrlab1' : unreferenced label +#pragma warning( disable : 4127 ) // C4127: conditional expression is constant +#pragma warning( disable : 4244 ) // C4244: '=' : conversion from 'int' to 'short', possible loss of data +#endif //__VC32__ + +#include "resource.h" +#include "parser.h" + +int yylex(); +void yyerror(const char* string, ...); +int yywrap(); +#define YYDEBUG 1 +extern int yylineno; + +#include "rcomp.hpp" +#include "datatype.h" +#include "mem.h" +#include "rcbinstr.h" +#include "rcscan.h" +#include "errorhan.h" +#include "fileacc.h" +#include "version.h" +#include "ctable.h" +#include "localise.h" +#include "main.h" + +#if defined(__VC32__) && !defined(_DEBUG) +#pragma warning( disable : 4702 ) // unreachable code +#pragma warning( disable : 4102 ) // 'yyerrlabel' : unreferenced label +#pragma warning( disable : 4244 ) // '=' : conversion from 'int' to 'short', possible loss of data +#endif + + + +String::CharacterSet CharacterSetID( const String & character_set_name ); +void asUTF8(char* aUtf8, int aUnicode); +void SetIdFromName( const String & NameStatementValue); +void CheckStructUsage(); + +unsigned short & d = MemCheckControl::iLogMemory; + +StructHeader * pSH; + +StructHeaderArray * pSHA; // Used in resource struct handling functions. +ResourceHeader * pResourceHeader; +ResourceItemArray * pCurrentRIA; +StringArray * pUsedLabelsArray = new StringArray(); +int verbose; +String::CharacterSet SourceCharacterSet = String::CP1252; +String::CharacterSet TargetCharacterSet = String::CP1252; +unsigned short logmemorysetting; +int * pCurrentLineNumber; +FileLineManager * pFileLineHandler; +NameIdMap * pResourceNameIds; +long CurrentEnumValue; +String CurrentEnumName; +char TempStr[300]; +rcscan * pScan; + +int CurrentIdStep=1; +long CurrentId=0; +int FormatIdAsHex=0; // defaults to decimal, changes in SetIdFromName + +unsigned long Uid2=0; +unsigned long Uid3=0; + + + +const String Divider("*******************************************"); + +#define REGISTER_LINE ErrorHandler::Register(pFileLineHandler->GetCurrentFile(), pFileLineHandler->GetErrorLine(* pCurrentLineNumber)) + +// Convert a string containing a character literal in aQuoted +// into a value suitable for LCHAR_LITERAL +void SetCharacterLiteral(char* aOut, const String& aQuoted) + { + UTF16 first; + int length=1; + if (aQuoted.Length() < 1 ) + { + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Warning: Empty Character literal"); + } + if (aQuoted.Length() > 1 ) + { + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Error: String Literal length greater than 1"); + exit(1); + } + if (aQuoted.Export(&first, length, SourceCharacterSet)==0) + { + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Warning: Ignoring trailing characters in character literal"); + } + sprintf(aOut, "%d", first); + } + +%} + +%union { + char Value[1024*8]; + TValueMaybeRls ValueMaybeRls; + unsigned long Id; + StructItem * pStructItem; + SimpleStructItem * pSimpleStructItem; + ArrayStructItem * pArrayStructItem; + StructArrayStructItem * pStructArrayStructItem; + StringArray * pStringArray; + long NumInitialiser; + TRlsQualifiers RlsQualifiers; + TRlsType RlsType; +} + +%token L_STRUCT L_RESOURCE L_NAME L_OFFSET L_SYSTEM L_GLOBAL L_LOCAL L_CHARACTER_SET +%token L_BUF L_WORD L_BYTE L_LONG L_DOUBLE L_TEXT L_LTEXT L_LINK L_LLINK L_SRLINK +%token L_BUF8 L_TEXT8 L_LTEXT8 L_BUF16 L_TEXT16 L_LTEXT16 L_UID_TWO L_UID_THREE +%token L_RLS_STRING L_RLS_STRING8 L_RLS_DOUBLE +%token L_RLS_BYTE L_RLS_WORD L_RLS_LONG +%token L_MULTI +%token L_TAG_START L_TAG_END +%token L_TAG_COMMAND L_TAG_WORD L_TAG_NEW_LINE +%token L_LABEL L_NUM_NATURAL L_NUM_FLOAT L_NATURAL_EXPR L_ENUM +%token L_LEN +%token L_CHAR_LITERAL L_STRING_LITERAL + +%type data_type len_declaration +%type struct_item array_struct_item simple_struct_item +%type simple_struct_item_start +%type struct_type_struct_item struct_array_struct_item +%type array_struct_item_start array_struct_item_base +%type struct_array_struct_item_base +%type simple_initialiser natural_expression +%type character_code_expression string_expression string_expression_item +%type simple_initialiser_list +%type natural_expression_numeric +%type rls_qualifiers rls_cardinality +%type rls_label +%type rls_string_item rls_num_item rls_float_item + +%left '+' '-' +%left '*' '/' +%left '|' +%left UMINUS + +%% + +/*****************************************************************/ +/* TOP-MOST RULE */ +/*****************************************************************/ +source : statement_list { if(verbose) { MOFF; cout << Divider << "\n" << Divider << endl; MON; } + } +; +/*****************************************************************/ +/* statement-list and statement */ +/*****************************************************************/ +statement_list: + statement_list statement +| statement_list comment_tag +| /* Nothing */ +; + +statement: + struct_statement maybe_semicolon +| resource_statement maybe_semicolon +| character_set_statement maybe_semicolon +| name_statement maybe_semicolon +| offset_statement maybe_semicolon +| system_statement maybe_semicolon +| enum_statement +| uidX_statement maybe_semicolon +| rls_item_statement maybe_semicolon +; + +maybe_semicolon: + ';' + { + // This is my gift to the world: no more "syntax error" for adding + // an extra semicolon at the end of a struct or resource. + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Warning: unnecessary semicolon"); + } +| +; + +/******************************************************************/ +/* STRUCT statement */ +/******************************************************************/ +struct_statement: + struct_statement_start struct_item_list '}' + { if(verbose) { MOFF; cout << Divider << "\n" << * pSH << Divider << endl; MON;} } +; +struct_statement_start: + L_STRUCT L_LABEL maybe_comment_tag '{' + { if(verbose) { MOFF;cout << "struct_statement_start " << $2 << endl; MON;} + pSH = new StructHeader($2); + REGISTER_LINE; + pG->SHA.Add(pSH); + } +| L_STRUCT L_LABEL len_declaration maybe_comment_tag '{' + { if(verbose) { RCTypeArray Types; MOFF;cout << "struct_statement_start " << $2 << " " << Types.GetName($3) << endl; MON;} + pSH = new StructHeader($2, $3); + REGISTER_LINE; + pG->SHA.Add(pSH); + } +| L_STRUCT L_LABEL L_LEN maybe_comment_tag '{' + { if(verbose) { MOFF;cout << "struct_statement_start " << $2 << " (WORD)" << endl; MON;} + pSH = new StructHeader($2, L_WORD); + REGISTER_LINE; + pG->SHA.Add(pSH); + } +; +struct_item_list: + struct_item_list struct_item ';' { if(verbose) { MOFF;cout << "struct_item_list Adding struct_item." << endl; MON;} + REGISTER_LINE; + pSH->iSIA.Add($2); + } +| struct_item_list comment_tag struct_item ';' { if(verbose) { MOFF;cout << "tagged struct_item_list Adding struct_item." << endl; MON;} + REGISTER_LINE; + pSH->iSIA.Add($3); + } +| /* Nothing */ +; +struct_item: + simple_struct_item +| array_struct_item +| struct_type_struct_item +| struct_array_struct_item +; +simple_struct_item: + simple_struct_item_start { $$ = $1;} +| simple_struct_item_start '(' natural_expression ')' + { if(verbose) { MOFF;cout << " Limit: " << $3 << endl; MON;} + $1->iLengthLimit = $3; + $$ = $1; + } +| simple_struct_item_start '=' simple_initialiser /****************************************************************/ + { if(verbose) { MOFF;cout << " Default: " << $3 << endl; MON;} + $1->iDefault = $3; + $$ = $1; + } +| simple_struct_item_start '(' natural_expression ')' '=' string_expression /****************************************************************/ + { if(verbose) { MOFF;cout << " Limit: " << $3 << ", Default: " << $6 << endl; MON;} + NumericValue Limit($3, L_LONG); + if(String($6).ExportLength(TargetCharacterSet,SourceCharacterSet) > Limit.GetULong() ) + { + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Text length exceeds specified limit"); + exit(1); + } + $1->iLengthLimit = $3; + $1->iDefault = $6; + $$ = $1; + } + +; +simple_struct_item_start: + data_type L_LABEL { if(verbose) + { + RCTypeArray Types; + MOFF;cout << "simple_struct_item " << Types.GetName($1) << " " << $2 << endl; MON; + } + $$ = new SimpleStructItem($1,$2); + assert($$ != NULL); + } +| data_type '<' natural_expression_numeric '>' L_LABEL + { if(verbose) + { RCTypeArray Types; + MOFF;cout << "simple_struct_item " << Types.GetName($1) << " " << $5 << endl; MON; + } + String s(NumericValue::ltoa($3)); + $$ = new SimpleStructItem($1,$5,s); + assert($$ != NULL); + } +; + +/* Note that generic text identifiers are converted to their explicit + 8 or 16-bit forms at this point, depending on the target character set. +*/ +data_type: + L_BYTE { $$ = L_BYTE;} +| L_WORD { $$ = L_WORD;} +| L_LONG { $$ = L_LONG;} +| L_DOUBLE { $$ = L_DOUBLE;} + + + +| L_TEXT + { + $$ = ( TargetCharacterSet == String::Unicode ) ? L_TEXT16: L_TEXT8; + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Warning: Deprecated use of zero-terminated TEXT - use LTEXT instead"); + } +| L_LTEXT + { + $$ = ( TargetCharacterSet == String::Unicode ) ? L_LTEXT16: L_LTEXT8; + } +| L_BUF + { + $$ = ( TargetCharacterSet == String::Unicode ) ? L_BUF16: L_BUF8; + } + + + +| L_TEXT8 { $$ = L_TEXT8; + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Warning: Deprecated use of zero-terminated TEXT8 - use LTEXT8 instead"); + } +| L_TEXT16 { $$ = L_TEXT16; + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Warning: Deprecated use of zero-terminated TEXT16 - use LTEXT16 instead"); + } +| L_LTEXT8 { $$ = L_LTEXT8;} +| L_LTEXT16 { $$ = L_LTEXT16;} +| L_BUF8 { $$ = L_BUF8;} +| L_BUF16 { $$ = L_BUF16;} +| L_LINK { $$ = L_LINK;} +| L_LLINK { $$ = L_LLINK;} +| L_SRLINK { $$ = L_SRLINK;} +; +array_struct_item: + array_struct_item_base { $$ = $1;} +| array_struct_item_base '=' '{' simple_initialiser_list '}' + { if(verbose) { MOFF;cout << "array_struct_item with simple_initialiser_list" << endl;MON;} + $1->iDefaults = * $4; + if($1->iSize.Length() > 0) + { + NumericValue v($1->iSize, L_LONG); + REGISTER_LINE; + if($4->Size()!=long(v.GetULong())) + { + ErrorHandler::OutputErrorLine("Size does not match number of initialisers"); + exit(1); + } + } + $$ = $1; + delete $4; + } +; +array_struct_item_base: + array_struct_item_start ']' { if(verbose) { MOFF;cout << "array_struct_item_base with no size" << endl;MON;} + $$ =$1; + } +| array_struct_item_start natural_expression ']' + { if(verbose) { MOFF;cout << "array_struct_item_base with size " << $2 << endl;MON;} + $1->iSize = $2; + $$ = $1; + } +| L_LEN len_declaration array_struct_item_start ']' + { if(verbose) + { RCTypeArray Types; + MOFF;cout << "array_struct_item_base with LenType " << Types.GetName($2) << endl;MON; + } + $3->iLenType = $2; + $$ = $3; + } +| L_LEN len_declaration array_struct_item_start natural_expression ']' + { if(verbose) + { RCTypeArray Types; + MOFF;cout << "array_struct_item_base with size " << $4 << " and LenType " << Types.GetName($2) << endl;MON; + } + $3->iLenType = $2; + $3->iSize = $4; + $$ = $3; + } +; +array_struct_item_start: + data_type L_LABEL '[' { if(verbose) + { RCTypeArray Types; + MOFF;cout << "array_struct_item_start " << Types.GetName($1) << " " << $2 << endl;MON; + } + $$ = new ArrayStructItem($1, $2); + } +; +len_declaration: + L_BYTE { $$ = L_BYTE;} +| L_WORD { $$ = L_WORD;} +; +struct_type_struct_item: + L_STRUCT L_LABEL { if(verbose) { MOFF;cout << "struct_type_struct_item " << $2 << endl;MON;} + $$ = new StructTypeStructItem($2); + } +; +struct_array_struct_item: + struct_array_struct_item_base { $$ = $1;} +| L_LEN len_declaration struct_array_struct_item_base + { if(verbose) { RCTypeArray Types; MOFF;cout << "struct_array_struct_item - Setting Size to " << Types.GetName($2) << endl;MON;} + $3->iLenType = $2; $$ = $3; + } +; +struct_array_struct_item_base: + L_STRUCT L_LABEL '[' ']' { if(verbose) { MOFF;cout << "struct_array_struct_item_base " << $2 << endl;MON;} + $$ = new StructArrayStructItem($2); + } +| L_STRUCT L_LABEL '[' natural_expression ']' + { if(verbose) { MOFF;cout << "struct_array_struct_item_base " << $2 << " " << $4 << endl;MON;} + $$ = new StructArrayStructItem($2, $4); + } +; +/*********************************************************************/ +/* RESOURCE statement */ +/*********************************************************************/ +resource_statement: + resource_statement_start '{' resource_item_list '}' + { + pResourceHeader->AddDefault(); + CurrentId+=CurrentIdStep; + if(verbose) { MOFF;cout << "Resource ID "<< CurrentId << endl << Divider << "\n" << * pResourceHeader << Divider << endl;MON;} + pResourceHeader->SetResourceId(*pResourceNameIds,CurrentId,FormatIdAsHex); + pG->Index.Add(pResourceHeader); + + CheckStructUsage(); + + pUsedLabelsArray->Empty(); + + pResourceHeader = NULL; + } +; +resource_statement_start: + L_GLOBAL resource_statement_start_names {} /* Ignore GLOBAL (obsolete feature).*/ +| L_LOCAL resource_statement_start_names + { + if(verbose) { MOFF;cout << "resource_statement_start LOCAL" << endl;MON;} + assert(pResourceHeader != NULL); + pResourceHeader->iLocal = 1; + } +| resource_statement_start_names {} +; +resource_statement_start_names: + L_RESOURCE L_LABEL L_LABEL { if(verbose) { MOFF;cout << "resource_statement_start_names " << $2 << " " << $3 << endl;MON;} + assert(pResourceHeader == NULL); + pResourceHeader = new ResourceHeader($3); + pCurrentRIA = & (pResourceHeader->iRIA); + REGISTER_LINE; + if(pResourceNameIds->IsStored($3)) + { + ErrorHandler::OutputErrorLine("Resource with this name encountered already"); + exit(1); + } + pCurrentRIA->FillFromStruct($2); + pG->AllIdentifiers.Add(new String($3)); // Add label to store + } +| L_RESOURCE L_LABEL { if(verbose) { MOFF;cout << "resource_statement_start_names " << $2 << " " << endl;MON;} + assert(pResourceHeader == NULL); + pResourceHeader = new ResourceHeader; + pCurrentRIA = & (pResourceHeader->iRIA); + REGISTER_LINE; + pCurrentRIA->FillFromStruct($2); + } +; +resource_item_list: + resource_item_list resource_item ';'{ if(verbose) { MOFF;cout << "resource_item_list" << endl;MON;}} +| resource_item_list comment_tag resource_item ';'{ if(verbose) { MOFF;cout << "tagged resource_item_list" << endl;MON;}} +| resource_item_list error ';' { yyerrok; yyclearin; } +| /* Nothing */ +; +resource_item: + L_LABEL '=' simple_initialiser { if(verbose) { MOFF;cout << "resource_item " << $1 << " " << $3 << endl;MON;} + REGISTER_LINE;/****************************************************************/ + pCurrentRIA->Set($1, $3); + } +| resource_simple_array_item +| struct_resource_item +| struct_array_resource_item +; +resource_simple_array_item: + L_LABEL '=' '{' '}' + { + if (verbose) + { MOFF;cout << "resource_simple_array_item " << $1 << endl;MON;} + } +| L_LABEL '=' '{' simple_initialiser_list '}' + { + if (verbose) + { MOFF;cout << "resource_simple_array_item " << $1 << " with simple_initialiser_list" << endl;MON;} + REGISTER_LINE; + pCurrentRIA->Set($1, * $4); + delete $4; + } +; + +/*---------------------------------------------------------------------------*/ +/* A note about RIAStack, SRIStack and pCurrentRIA. */ +/* */ +/* RIA stands for Resource Item Array. */ +/* SRI stands for Struct Array Resource Item. */ +/* */ +/* A push to RIAStack is made when dropping inside a STRUCT or STRUCT[] in */ +/* order to set values for the components. When this happens pCurrentRIA is */ +/* set to the RIA for the STRUCT or last item of the STRUCT[]. */ +/* */ +/* pCurrentRIA is set to the result of popping from RIAStack when a closing */ +/* brace is reached. */ +/* */ +/* A push is made to SRIStack when going into an item for a STRUCT[]. On */ +/* reaching a closing brace the STRUCT[] is popped off the SRIStack. An new */ +/* item may then be added to this array. */ +/*---------------------------------------------------------------------------*/ +struct_resource_item: + struct_resource_item_start resource_item_list '}' + { if(verbose) { MOFF;cout << "struct_resource_item" << endl;MON;} + pCurrentRIA = pG->RIAStack.Pop(); + } +; +struct_resource_item_start: + L_LABEL '=' L_LABEL '{' { if(verbose) { MOFF;cout << "struct_resource_item_start " << $1 << " " << $3 << endl;MON;} + REGISTER_LINE; + pCurrentRIA->Set($1, $3); + String * thisLabel = new String($1); + pUsedLabelsArray->Add(thisLabel); + // in here add the label to a temp store + pG->RIAStack.Push(pCurrentRIA); + pCurrentRIA = pCurrentRIA->Find($1)->GetRIA(); + } +; +struct_array_resource_item: + struct_array_resource_item_start struct_array_resource_item_list_top '}' + { if(verbose) { MOFF;cout << "struct_array_resource_item" << endl;MON;} + pG->SRIStack.Pop(); + } +| struct_array_resource_item_start struct_array_resource_item_list_top error + { pG->SRIStack.Pop();} +; +struct_array_resource_item_start: + L_LABEL '=' '{' L_LABEL '{' { if(verbose) { MOFF;cout << "struct_array_resource_item_start " << $1 << " " << $4 << endl;MON;} + ResourceItem * p = pCurrentRIA->Find($1); + pG->SRIStack.Push(p); + REGISTER_LINE; + String * thisLabel = new String($1); + pUsedLabelsArray->Add(thisLabel); + // in here add the label to a temp store + p->Set($4); + pG->RIAStack.Push(pCurrentRIA); + pCurrentRIA = p->GetRIA(); + } +; +struct_array_resource_item_list_top: + struct_array_resource_item_list_top_start +| struct_array_resource_item_list_top_start ',' struct_array_resource_item_list +| struct_array_resource_item_list_top_start ',' error +; +struct_array_resource_item_list_top_start: + resource_item_list '}' { if(verbose) { MOFF;cout << "struct_array_resource_item_list_top " << endl;MON;} + pCurrentRIA = pG->RIAStack.Pop(); + } +; +struct_array_resource_item_list: + struct_array_resource_item_list_item +| struct_array_resource_item_list ',' struct_array_resource_item_list_item +; +struct_array_resource_item_list_item: + struct_array_resource_item_list_item_start resource_item_list '}' + { if(verbose) { MOFF;cout << "struct_array_resource_item_list_item " << endl;MON;} + pCurrentRIA = pG->RIAStack.Pop(); + } +; +struct_array_resource_item_list_item_start: + L_LABEL '{' { if(verbose) { MOFF;cout << "struct_array_resource_item_list_item_start " << $1 << endl;MON;} + ResourceItem * p = pG->SRIStack.Peek(); + REGISTER_LINE; + p->Set($1); + pG->RIAStack.Push(pCurrentRIA); + pCurrentRIA = p->GetRIA(); + } +; + + +/*****************************************************************/ +/* simple_initialiser and simple_initialiser_list */ +/*****************************************************************/ +simple_initialiser: + L_NUM_FLOAT +| L_CHAR_LITERAL + { + // convert literal to unsigned long value of 1st character + SetCharacterLiteral($$, $1); + } +| string_expression +| natural_expression +; +simple_initialiser_list: + simple_initialiser + { + if(verbose) + { + MOFF;cout << "simple_initialiser_list - single string " << $1 << endl;MON; + } + + $$ = new StringArray; + $$->Add(new String($1) ); + } +| simple_initialiser_list ',' simple_initialiser + { if(verbose) { MOFF;cout << "simple_initialiser_list - part of list " << $3 << endl;MON;} + assert($1 != NULL); + $1->Add(new String($3 ) ); + $$ = $1; + } +; + +natural_expression: + natural_expression_numeric { String s(NumericValue::ltoa($1) ); strcpy($$, s.GetAssertedNonEmptyBuffer() ); } +; +natural_expression_numeric: + L_NUM_NATURAL { if(verbose) { MOFF;cout << "Converting number " << $1 << endl;MON;} + REGISTER_LINE; + NumericValue v($1, L_LONG); $$ = (long)v.GetULong(); + } +| natural_expression_numeric '+' natural_expression_numeric { $$ = $1 + $3; } +| natural_expression_numeric '-' natural_expression_numeric { $$ = $1 - $3; } +| natural_expression_numeric '*' natural_expression_numeric { $$ = $1 * $3; } +| natural_expression_numeric '/' natural_expression_numeric { $$ = $1 / $3; } +| natural_expression_numeric '|' natural_expression_numeric { $$ = $1 | $3; } +| '-' natural_expression_numeric %prec UMINUS { if (!NumericValue::CheckSigned($2,L_LONG)) + { + REGISTER_LINE; + ErrorHandler::OutputErrorLine("Signed value too low"); + exit(1); + } + $$ = - $2; + } +| '(' natural_expression_numeric ')' { $$ = $2; } +; +string_expression: + string_expression_item +| string_expression_item string_expression { + if (strlen($$)+strlen($2) > sizeof($$)-1) + { + REGISTER_LINE; + ErrorHandler::OutputErrorLine("String expression is too long"); + exit(1); + } + strcat($$, $2); + } +; +string_expression_item: + L_STRING_LITERAL +| character_code_expression +| L_LABEL + { + const char * fileName = (*ErrorHandler::GetFileName()).GetBuffer(); + int lineNumber = ErrorHandler::GetLineNumber(); + QualifiedString * thisLabel = new QualifiedString($1, new String(fileName), lineNumber); + // store the label in the UsedIdentifiers array for checking + // whether label was declared + pG->UsedIdentifiers.Add(thisLabel); + + if (pG->EnumValues.IsStored($1)) + { + sprintf($$, "%d", pG->EnumValues.FindId($1)); + } + else if (pG->RlsNameIndex.count($1)) // if rls item has already been defined + { + // Found a reference to an rls_string. + RlsValue &rv = pG->RlsValues[pG->RlsNameIndex[$1]]; + ++rv.iCitationCount; // iCitationCount counts the number of times this rls value has been referneced + // Warn for multiple uses if 'multi' keyword not used. + if (1 < rv.iCitationCount && rv.iCardinality == ERlsCardinalitySingle) + { + Message * message = pG->Messages.GetEntry(LT_001); + String fileLine = *(rv.iFileName); + if(message->GetActivated()) + { + pGL->AddWarningToStore(fileLine, rv.iLineNumber, message->GetMessageOutput()); + } + REGISTER_LINE; + if (!pG->WarningMultiExplained) + { + Message * message = pG->Messages.GetEntry(LT_002); + fileLine = String(*(pFileLineHandler->GetCurrentFile())); + if(message->GetActivated()) + { + pGL->AddWarningToStore(fileLine, pFileLineHandler->GetErrorLine(* pCurrentLineNumber), message->GetMessageOutput()); + pG->WarningMultiExplained = true; + } + } + } + switch (rv.iType) + { + // Strings and numbers are just copied to the next layer up. + case ERlsString: + case ERlsString8: + case ERlsByte: + case ERlsWord: + case ERlsLong: + case ERlsDouble: + strcpy($$, rv.iValue.GetBuffer()); + break; + // Anything else is a character: this is converted to a number. + case ERlsStringChar: + case ERlsByteChar: + case ERlsWordChar: + case ERlsLongChar: + SetCharacterLiteral($$, rv.iValue); + break; + default: + Message * message = pG->Messages.GetEntry(LT_031); + if(message->GetActivated()) + { + ErrorHandler::OutputErrorLine(message->GetMessageOutput()); + exit(1); + } + break; + } + } + else + { + /* + Could be a reference to another resource, perhaps even a forward reference: + the OverwriteLink functions do FindId again when writing out the data. + Sadly this also permits things which are really syntax errors, inadvertently + converting labels into string literals.. + */ + } + } +; +character_code_expression: + '<' natural_expression_numeric '>' + { + REGISTER_LINE; + if($2 < 0 || ($2 > 255 && TargetCharacterSet != String::Unicode)) + { + ErrorHandler::OutputErrorLine("Character code must be a number in the range 0 to 255."); + exit(1); + } + if (TargetCharacterSet != String::Unicode) + { + * $$ = char($2); * ($$ + 1) = '\0'; + } + else + { + if (SourceCharacterSet == String::CP1252) + { + if ( ($2 >= 0x80) && ($2 <= 0x9F ) ) // 80-9F are illegal Unicode values. + { + ErrorHandler::OutputErrorLine("Warning: Deprecated non-unicode value in source stream"); + } + * $$ = char(UnicodeEscape); + asUTF8($$ + 1, $2); + } + else + if (SourceCharacterSet == String::UTF8) + { + asUTF8($$, $2); + } + else + { + // Unsatisfactory, but do people use other character sets? + if ($2 > 255) + { + ErrorHandler::OutputErrorLine("Don't know how to handle character > 255"); + } + * $$ = char($2); * ($$ + 1) = '\0'; + } + } + } +; + + +/*****************************************************************/ +/* name_statement */ +/*****************************************************************/ +name_statement: + L_NAME L_LABEL + { + REGISTER_LINE; + SetIdFromName($2); + } +| L_NAME L_STRING_LITERAL + { + REGISTER_LINE; + SetIdFromName($2); + } +; + + +/*****************************************************************/ +/* uidX_statement */ +/*****************************************************************/ +uidX_statement: + L_UID_TWO natural_expression_numeric + { + REGISTER_LINE; + if ($2 == 0) + { ErrorHandler::OutputErrorLine("UID2 must be non-zero"); exit(1); } + if (Uid2 != 0) + { ErrorHandler::OutputErrorLine("Warning: overwriting previous UID2 value"); } + Uid2=$2; + if(verbose) + { MOFF;cout << "uidX_statement UID2 " << Uid2 << endl;MON;} + } +| L_UID_THREE natural_expression_numeric + { + REGISTER_LINE; + if ($2 == 0) + { ErrorHandler::OutputErrorLine("UID3 must be non-zero"); exit(1); } + if (Uid3 != 0) + { ErrorHandler::OutputErrorLine("Warning: overwriting previous UID3 value"); } + Uid3=$2; + if(verbose) + { MOFF;cout << "uidX_statement UID3 " << Uid3 << endl;MON;} + } +; + + +/*****************************************************************/ +/* character_set_statement */ +/* Defines the SOURCE character set. Note that Unicode is a */ +/* character set id, but we can't read Unicode source */ +/* (because LEX and YACC can't handle it) */ +/*****************************************************************/ + +character_set_statement: + L_CHARACTER_SET L_LABEL { if(verbose) { MOFF;cout << "character_set_statement " << $2 << endl;MON;} + REGISTER_LINE; + SourceCharacterSet = CharacterSetID($2); + if ( SourceCharacterSet == String::UNKNOWN ) + { + String err = "Warning: Unrecognised character set name '"; + err += $2; + err += "'"; + ErrorHandler::OutputErrorLine(err); + } + if ( SourceCharacterSet == String::Unicode ) + { + SourceCharacterSet = String::UNKNOWN; + ErrorHandler::OutputErrorLine("Unicode source is unsupported"); + } + } +; + + + +/*****************************************************************/ +/* offset_statement */ +/*****************************************************************/ +offset_statement: + L_OFFSET natural_expression { if(verbose) { RCTypeArray Types; + MOFF;cout << "offset_statement " << $2 << endl;MON; } + REGISTER_LINE; + CurrentId=((long) NumericValue($2, L_LONG).GetULong() ); + } +; + +/*****************************************************************/ +/* system_statement */ +/*****************************************************************/ +system_statement: + L_SYSTEM { if(verbose) { MOFF;cout << "system_statement" << endl;MON;} + CurrentIdStep=-1; + } +; + +/*****************************************************************/ +/* enum_statement */ +/*****************************************************************/ +enum_statement: + enum_statement_start enum_list '}' +| enum_statement_start enum_list '}' ';' +; +enum_statement_start: + L_ENUM L_LABEL '{' + { + if(verbose) + { MOFF;cout << "enum_statement" << endl;MON;} + CurrentEnumName = $2; + CurrentEnumValue=0; + } +| L_ENUM '{' + { + if(verbose) + { MOFF;cout << "enum_statement" << endl;MON;} + CurrentEnumName = ""; + CurrentEnumValue=0; + } +; + +enum_list_entry: + L_LABEL + { + pG->EnumValues.Add($1, CurrentEnumValue++); + pG->AllIdentifiers.Add(new String($1)); // Add label to store + } +| L_LABEL '=' simple_initialiser + { + CurrentEnumValue = atol($3); + pG->EnumValues.Add($1, CurrentEnumValue); + CurrentEnumValue++; // Increment so that next field has value ($3+1) + pG->AllIdentifiers.Add(new String($1)); // Add label to store + } +; + + +enum_list: + maybe_comment_tag enum_list_entry +| enum_list ',' maybe_comment_tag enum_list_entry +; + +/************************/ +/* rls_xxxx statement */ +/************************/ +rls_item_statement: + rls_string_item rls_qualifiers rls_label string_expression + { + pG->RlsNameIndex[$3] = pG->RlsValues.size(); + pG->RlsValues.push_back(RlsValue(ErrorHandler::GetFileName(), + ErrorHandler::GetLineNumber(), $4, $1, + $2.iCardinality, $2.iMaxLength)); + if($2.iMaxLength + < String($4).ExportLength(TargetCharacterSet,SourceCharacterSet)) + { + Message * message = pG->Messages.GetEntry(LT_032); + if(message->GetActivated()) + { + ErrorHandler::OutputErrorLine(message->GetMessageOutput()); + exit(1); + } + } + } +| rls_string_item rls_qualifiers rls_label L_CHAR_LITERAL /* This section is only for compatibility */ + { + Message * message = pG->Messages.GetEntry(LT_033); + String fileName = *(pFileLineHandler->GetCurrentFile()); + int lineNumber = pFileLineHandler->GetErrorLine(* pCurrentLineNumber); + if(message->GetActivated()) + { + pGL->AddWarningToStore(fileName, lineNumber, message->GetMessageOutput()); + } + //... + /* Produce a warning "rls_string used for character constant: use rls_long, rls_word or rls_byte" */ + pG->RlsNameIndex[$3] = pG->RlsValues.size(); + pG->RlsValues.push_back(RlsValue(ErrorHandler::GetFileName(), + ErrorHandler::GetLineNumber(), $4, ERlsStringChar, + $2.iCardinality)); + } +| rls_float_item rls_cardinality rls_label L_NUM_FLOAT + { + pG->RlsNameIndex[$3] = pG->RlsValues.size(); + pG->RlsValues.push_back(RlsValue(ErrorHandler::GetFileName(), + ErrorHandler::GetLineNumber(), $4, $1, + $2.iCardinality)); + } +| rls_num_item rls_cardinality rls_label L_NUM_NATURAL + { + pG->RlsNameIndex[$3] = pG->RlsValues.size(); + pG->RlsValues.push_back(RlsValue(ErrorHandler::GetFileName(), + ErrorHandler::GetLineNumber(), $4, $1, + $2.iCardinality)); + } +| rls_num_item rls_cardinality rls_label L_CHAR_LITERAL + { + TRlsType rlsCharType = $1 == ERlsByte? ERlsByteChar + : ( $1 == ERlsWord? ERlsWordChar : ERlsLongChar ); + pG->RlsNameIndex[$3] = pG->RlsValues.size(); + pG->RlsValues.push_back(RlsValue(ErrorHandler::GetFileName(), + ErrorHandler::GetLineNumber(), $4, rlsCharType, + $2.iCardinality)); + } +; + +rls_label: L_LABEL + { + // Register line even if no warning here so that + // the rls_ item knows which line the label was on. + // Without this, the line registered would be the + // line following the declaration. + REGISTER_LINE; + strcpy($$, $1); + + if (pG->RlsNameIndex.count($1) != 0) + { + Message * message = pG->Messages.GetEntry(LT_003); + if(message->GetActivated()) + { + ErrorHandler::OutputErrorLine(message->GetMessageOutput()); + } + } + pG->AllIdentifiers.Add(new String($1)); // Add label to store + } + +rls_qualifiers: + '<' L_NUM_NATURAL '>' rls_cardinality + { + NumericValue v($2, L_LONG); + $$.iMaxLength = v.GetULong(); + $$.iCardinality = $4.iCardinality; + } +| rls_cardinality + { $$ = $1; } +; + +rls_cardinality: + L_MULTI + { + $$.iMaxLength = 0xFFFFFFF; + $$.iCardinality = ERlsCardinalityMultiple; + } +| + { + $$.iMaxLength = 0xFFFFFFF; + $$.iCardinality = ERlsCardinalitySingle; + } +; + +rls_string_item: + L_RLS_STRING + { $$ = ERlsString; } +| L_RLS_STRING8 + { $$ = ERlsString8; } +; + +rls_num_item: + L_RLS_BYTE + { $$ = ERlsByte; } +| L_RLS_WORD + { $$ = ERlsWord; } +| L_RLS_LONG + { $$ = ERlsLong; } +; + +rls_float_item: + L_RLS_DOUBLE + { $$ = ERlsDouble; } +; + +/************************/ +/* comment tags */ +/************************/ +maybe_comment_tag: + comment_tag +| +; + +comment_tag: + L_TAG_START tag_line L_TAG_END {ErrorHandler::Register(pFileLineHandler->GetCurrentFile(), pFileLineHandler->GetErrorLine(*pCurrentLineNumber)); } + ; + +tag_line: + tag_line tag_word + +| +; + +tag_word: + L_TAG_NEW_LINE { pGL->StoreComment($1); } +| L_TAG_COMMAND { pGL->StoreComment($1); } +| L_TAG_WORD { pGL->StoreComment($1); } +; + +%% + +// Function section +// ================ + +void asUTF8(char* aUtf8, int aUnicode) + { + if ( aUnicode > 0xffff ) + { + if ( aUnicode > 0x10ffff ) + { + ErrorHandler::OutputErrorLine("Surrogate character code must be a number in the range 0x10000 to 0x10ffff"); + exit(1); + } + + UTF16 high = (UTF16)(0xD7C0 + (aUnicode >> 10)); // high surrogate + UTF16 low = (UTF16)(0xDC00 | (aUnicode & 0x3FF)); // low surrogate + + *aUtf8++ =(char)(0xe0|(high>>12)); + *aUtf8++ =(char)(0x80|((high>>6)&0x3f)); + *aUtf8++ =(char)(0x80|(high&0x3f)); + *aUtf8++ =(char)(0xe0|(low>>12)); + *aUtf8++ =(char)(0x80|((low>>6)&0x3f)); + *aUtf8 =(char)(0x80|(low&0x3f)); + } + else if ((aUnicode & 0xff80) == 0x0000) + { + *aUtf8 = (char)aUnicode; + } + else if ((aUnicode & 0xf800) == 0x0000) + { + *aUtf8++ =(char)(0xc0|(aUnicode>>6)); + *aUtf8 =(char)(0x80|(aUnicode&0x3f)); + } + else + { + *aUtf8++ =(char)(0xe0|(aUnicode>>12)); + *aUtf8++ =(char)(0x80|((aUnicode>>6)&0x3f)); + *aUtf8 =(char)(0x80|(aUnicode&0x3f)); + } + *++aUtf8 = '\0'; + } + + +String::CharacterSet CharacterSetID( const String & character_set_name ) +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Return a character set ID from a character set name. The value UNKNOWN +// is returned if the name is not recognised. +// ---------------------------------------------------------------------------- +{ + String::CharacterSet ids[] = { String::ISOLatin1, String::ASCII, String::CP1252 + , String::CP850, String::ShiftJIS, String::Unicode + , String::UTF8 + , String::UNKNOWN + }; + String names[] = { "ISOLATIN1", "ASCII", "CP1252", "CP850", "SHIFTJIS", "UNICODE", "UTF8" }; + + for ( int i=0; ids[i]!=String::UNKNOWN; i++ ) + { + if ( names[i] == character_set_name ) return ids[i]; + } + + return String::UNKNOWN; + +} // end of CharacterSetID code + +void SetIdFromName( const String & NameStatementValue) + { + // space 0 + // A 1 + // B 2 + // ... + // Z 26 + // + // ABCD corresponds to the number 4321 which becomes ( (4*27 + 3) * 27 + 2) * 27 + 1. + + if(verbose) + { MOFF;cout << "name_statement " << NameStatementValue << endl;MON;} + if ( NameStatementValue.Length() > 4) + { + ErrorHandler::OutputErrorLine( "Name must be no longer than four characters"); + exit( 1); + } + + long NewId = 0; + + for( unsigned long i = 0; i < NameStatementValue.Length(); i++) + { + NewId *= 27; + if ( isalpha( NameStatementValue[i]) ) + NewId += toupper( NameStatementValue[i]) - 'A' + 1; + } + + CurrentId = NewId << 12; + FormatIdAsHex = 1; + if(verbose) + { MOFF;cout << "Current id " << CurrentId << endl;MON;} + } + +void RlsUnusedWarnings() + { + TNameIndex::iterator end = pG->RlsNameIndex.end(); + for (TNameIndex::iterator i = pG->RlsNameIndex.begin(); i != end; ++i) + { + int index = i->second; + RlsValue& v = pG->RlsValues[index]; + if (v.iCitationCount == 0) + { + Message * message = pG->Messages.GetEntry(LT_004); + String fileLine = *(v.iFileName); + if(message->GetActivated()) + { + pGL->AddWarningToStore(fileLine, v.iLineNumber, message->GetMessageOutput()); + } + } + } + } + +int ParseSourceFile(FILE* aFile, unsigned short aYYDebug) + { + // Set up various global pointers which refer to the pG structure + pSHA = & (pG->SHA); + pFileLineHandler = & (pG->FileLineHandler); + pResourceNameIds = & (pG->ResourceNameIds); + + pScan = new rcscan(pG->FileLineHandler, aFile); + + yydebug = aYYDebug; + pCurrentLineNumber = &yylineno; + int ReturnValue = yyparse(); + + RlsUnusedWarnings(); + + int bScanErrorFound = pScan->ErrorWasFound(); + + delete pScan; + pScan = NULL; + + if(ReturnValue != 0) + return ReturnValue; + + if(bScanErrorFound) + return 1; + + return 0; // successful parse - parse tree now in the pG data structure + } + + +void CheckStructUsage() + { + ResourceItemArrayIterator nextRI( *pCurrentRIA); + ResourceItem * pRI; + while ( ( pRI = nextRI() ) != NULL) + { + int resourceItemType = pRI->GetResourceItemType(); + String resourceItemLabel = pRI->GetLabel(); + if( (resourceItemType == EStructTypeResourceItem) || (resourceItemType == EStructArrayResourceItem) ) + { + StringArrayIterator nextLabel( *pUsedLabelsArray); + String * pLabel; + bool flag = false; + while ( ( ( pLabel = nextLabel() ) != NULL ) && (! flag) ) + { + StringLess stringCompare; + if( !stringCompare(resourceItemLabel,*pLabel) && !stringCompare(*pLabel,resourceItemLabel) ) + { + flag = true; + } + } + if(! flag) + { + if(resourceItemType == EStructTypeResourceItem) + { + Message * message = pG->Messages.GetEntry(LT_046); + if(message->GetActivated()) + { + String comment = message->GetMessageOutput(); + comment += "'"; + comment += resourceItemLabel; + comment += "'"; + ErrorHandler::OutputErrorLine(comment); + } + } + else + { + Message * message = pG->Messages.GetEntry(LT_047); + if(message->GetActivated()) + { + String comment = message->GetMessageOutput(); + comment += "'"; + comment += resourceItemLabel; + comment += "'"; + ErrorHandler::OutputErrorLine(comment); + } + } + } + } + } + } + +int yywrap() +{ + return 1; +} + +/* Called by yyparse on error */ +#include +void yyerror (const char *s, ...) +{ + va_list list; + va_start(list, s); + pScan->yyerror(const_cast(s), list); + va_end(list); +} + +