%{
// 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 <assert.h>
#include <ctype.h>
#include <string.h>
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
#include <fstream>
#include <iostream>
using namespace std;
using std::cout;
using std::endl;
#else //!__MSVCDOTNET__
#include <fstream.h>
#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 <Id> L_STRUCT L_RESOURCE L_NAME L_OFFSET L_SYSTEM L_GLOBAL L_LOCAL L_CHARACTER_SET
%token <Id> L_BUF L_WORD L_BYTE L_LONG L_DOUBLE L_TEXT L_LTEXT L_LINK L_LLINK L_SRLINK
%token <Id> L_BUF8 L_TEXT8 L_LTEXT8 L_BUF16 L_TEXT16 L_LTEXT16 L_UID_TWO L_UID_THREE
%token <Id> L_RLS_STRING L_RLS_STRING8 L_RLS_DOUBLE
%token <Id> L_RLS_BYTE L_RLS_WORD L_RLS_LONG
%token <Id> L_MULTI
%token <Id> L_TAG_START L_TAG_END
%token <Value> L_TAG_COMMAND L_TAG_WORD L_TAG_NEW_LINE
%token <Value> L_LABEL L_NUM_NATURAL L_NUM_FLOAT L_NATURAL_EXPR L_ENUM
%token <Value> L_LEN
%token <Value> L_CHAR_LITERAL L_STRING_LITERAL
%type <Id> data_type len_declaration
%type <pStructItem> struct_item array_struct_item simple_struct_item
%type <pSimpleStructItem> simple_struct_item_start
%type <pStructItem> struct_type_struct_item struct_array_struct_item
%type <pArrayStructItem> array_struct_item_start array_struct_item_base
%type <pStructArrayStructItem> struct_array_struct_item_base
%type <Value> simple_initialiser natural_expression
%type <Value> character_code_expression string_expression string_expression_item
%type <pStringArray> simple_initialiser_list
%type <NumInitialiser> natural_expression_numeric
%type <RlsQualifiers> rls_qualifiers rls_cardinality
%type <Value> rls_label
%type <RlsType> 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 << " <Resource not named>" << 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 <stdarg.h>
void yyerror (const char *s, ...)
{
va_list list;
va_start(list, s);
pScan->yyerror(const_cast<char*>(s), list);
va_end(list);
}