fix: make sure host attribute is set rather than blank in logs on windows by using the env var 'COMPUTERNAME' instead of 'HOSTNAME'. Thus make it less difficult to order recipes in the log by time.
%{
// 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);
}