// CPPParserSymPragma.cpp: Process #pragmas that are interesting,
// which is currently:
// #pragma pack(...)
#include "CPPParserSym.h"
#include "CPPSymTable.h"
///////////////////////////////////////////////////////////////////////
// HandlePragma: Process a #pragma directive
// Inputs:
// None explicitly, but uses LT(i), where LT(1) is assumed to be
// positioned at the PND_PRAGMA token
// Outputs: none
// Return: none
///////////////////////////////////////////////////////////////////////
// virtual
void
CPPParserSym::HandlePragma()
{
JLStr pragmaText = LT(2)->getText();
if (GetOption(OptPragmaMSPacking) && pragmaText == "pack")
{
HandleMSPacking();
}
}
///////////////////////////////////////////////////////////////////////
// HandleMSPacking: Process MS-specific packing pragma
// #pragma pack is one of the following forms, where nnn is an
// integer and id is an identifier
// #pragma pack()
// #pragma pack(nnn)
// #pragma pack(push)
// #pragma pack(push, nnn)
// #pragma pack(push, id)
// #pragma pack(push, id, nnn)
// #pragma pack(pop)
// #pragma pack(pop, id)
//
// Inputs:
// None explicitly, but uses LT(i), where LT(1) is assumed to be
// positioned at the PND_PRAGMA token
// Outputs: none
// Return: none
///////////////////////////////////////////////////////////////////////
void
CPPParserSym::HandleMSPacking()
{
bool doPush = false;
int idx = 3;
// The next token must be a "("
if (LT(idx)->getType() != TOK_LPAREN)
{
ReportError("Expected '(' after #pragma pack", LT(idx));
return;
}
idx++;
switch (LT(idx)->getType())
{
case TOK_RPAREN:
{
// #pragma pack() - restore default packing
symTable->SetDefaultPacking();
break;
}
case TOK_DECIMALINT:
{
// #pragma pack(nnn)
int newPacking = atoi(LT(idx)->getText());
if (
newPacking != 1 && newPacking != 2 &&
newPacking != 4 && newPacking != 8 &&
newPacking != 16
)
{
ReportError(JLStr("Invalid packing value: ") + LT(idx)->getText(), LT(idx));
return;
}
idx++;
// Must have a closing ")"
if (LT(idx)->getType() != TOK_RPAREN)
{
ReportError("Expected ')' after '#pragma pack(nnn' ", LT(idx));
return;
}
symTable->SetPacking(newPacking);
break;
}
case TOK_ID:
{
// Must be 'push' or 'pop'
if (strcmp(LT(idx)->getText(), "push") == 0)
{
doPush = true;
} else if (strcmp(LT(idx)->getText(), "pop") != 0)
{
ReportError("Expected 'push' or 'pop' after '#pragma pack(' ", LT(idx));
return;
}
idx++;
// If the next thing is 'comma identifier', skip it
if (LT(idx)->getType() == TOK_COMMA && LT(idx+1)->getType() == TOK_ID)
{
idx += 2;
}
if (doPush)
{
bool hasNewPacking = false;
int newPacking;
// Optional 'comma integer' for push
if (LT(idx)->getType() == TOK_COMMA && LT(idx+1)->getType()== TOK_DECIMALINT)
{
hasNewPacking = true;
idx++;
newPacking = atoi(LT(idx)->getText());
if (
newPacking != 1 && newPacking != 2 &&
newPacking != 4 && newPacking != 8 &&
newPacking != 16
)
{
ReportError(JLStr("Invalid packing value: ") + LT(idx)->getText(), LT(idx));
return;
}
idx++;
}
// Must have a closing ")"
if (LT(idx)->getType() != TOK_RPAREN)
{
ReportError("Expected ')' after '#pragma pack(push,integer' ", LT(idx));
return;
}
// Push the current packing value
symTable->PushPacking(newPacking);
} else {
// pop
if (symTable->GetPackingStackSize() < 2)
{
ReportError("'#pragma pack(pop' not matched with '#pragma pack(push'", LT(1));
return;
}
// Must have a closing ")"
if (LT(idx)->getType() != TOK_RPAREN)
{
ReportError("Expected ')' after '#pragma pack(pop' ", LT(idx));
return;
}
symTable->PopPacking();
}
break;
}
default:
ReportError("Expected 'push', 'pop', or integer after '#pragma pack(' ", LT(idx));
return;
}
idx++;
// Must not have more tokens
if (LT(idx)->getType() != TOK_PRAGMA_END)
{
ReportError("Unexpected tokens after '#pragma pack...' ", LT(idx));
return;
}
}