Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1504 lines
51 KiB

%{
/***********************************************************************/
/* mtcpars.y : Thunk Compiler input grammar for Yacc generated parser
*
* Created: 10/15/88 Kevin Ross Microsoft Corporation
*
*
* History:
* 10.12.90 Kevin Ruddell converted to thunk Win32, 16=>32
*
*
*/
/***********************************************************************/
/* This parser generates all of the data structures used by the thunk
* compiler. There are three types of data structures generated, and
* each is explained fully in the file types.h. Semantic information
* is given near each rule.
*
*/
/***********************************************************************/
#include <stdio.h>
#include "thunk.h"
#include "types.h"
#include "symtab.h"
#include "globals.h"
extern FILE *StdDbg;
static FunctionNode *MapF1, *MapF2;
static TypeNode *T1, *T2;
static TypeNode *T3, *T4;
static long iPushValue;
%}
%union
{
char *ident;
int intval;
TypeNode *type;
FunctionNode *func;
AllowNode *allow;
long longval;
}
%token syTypeDef
%token syMakeThunk
%token syArray
%token syStruct
%token <ident> syIdent
%token <longval> syNumber
%token <intval> syAPI16
%token <intval> syAPI32
%token syFar16
%token syNear32
%token syPtr /* used as both Pointer and Multiply operator */
%token syStack
%token syInline
%token sySysCall
%token syTrue
%token syFalse
%token sySizeOf
%token syCountOf
%token syPassIfHiNull
%token sySpecial
%token syMapToRetval
%token syReverseRC
%token syLocalHeap
%token syInOut
%token syOutput
%token syInput
%token syConforming
%token syByte
%token syWord
%token syDWord
%token syAligned
%token syDeleted
%token syTruncation
%token syEnableMapDirect1632
%token syUser
%token syGdi
%token syKernel
%token syNewElem
%token syErrNoMem
%token syErrBadParam
%token syErrUnknown
%token syNullType
%token syStruct
%token syPointer
%token syLong
%token syShort
%token syInt
%token syUnsigned
%token sySigned
%token syVoid
%token syChar
%token syString
%token syColon
%token sySemi
%token syComma
%token syPlus
%token syMinus
%token syDiv
%token syLParen
%token syRParen
%token syMapDirect
%token syEqual
%token syCaret
%token syTilde
%token syLAngle
%token syRAngle
%token syLBrack
%token syRBrack
%token syRBrace
%token syLBrace
%token syAllow
%token syRestrict
%token syError /* lex error */
%left syPlus,syMinus
%left syPtr,syDiv
%type <type> BaseType KnownType ParamDecl StructElem
%type <type> ParamList Parameters ExtendedBaseType
%type <type> KnownType TypeDecl StructList StructDef
%type <type> SemanticOp ParamType
%type <func> FunctionDecl
%type <intval> CallType Aligned Boolean PointerDecl ArrayDecl
%type <intval> Reserved CallSemantics StructSemantics RCCondition
%type <longval> Numeric
%type <allow> AllowList AllowValues Allow
%start Statements
%%
/******************************************************************************/
/******************************************************************************/
Statements : Statements Statement
{
}
| /* Empty statement OK */
;
/******************************************************************************/
/******************************************************************************/
/* A statement in the thunk language is either a typedef, a mapping
* declaration, a semantic declaration, or a mapping directive.
*/
Statement : syTypeDef TypeDecl
| Semantics
| Mapping
| MapDirect
;
/******************************************************************************/
/******************************************************************************/
/* These semantics are global to all API that are declared AFTER these
* statements. They set global values that are used in a Mapping statement
* when creating the mapping declarations
*/
Semantics : syErrBadParam syEqual Numeric sySemi
{
gErrBadParam = $3;
}
| syErrNoMem syEqual Numeric sySemi
{
gErrNoMem = $3;
}
| syErrUnknown syEqual Numeric sySemi
{
gfErrUnknown = 1;
gErrUnknown = $3;
}
| syUser syEqual Boolean sySemi
{
fUser = $3;
}
| syGdi syEqual Boolean sySemi
{
fGdi = $3;
}
| syKernel syEqual Boolean sySemi
{
fKernel = $3;
}
/* This semantic sets the stack size for all API that follow.
*/
| syStack syEqual Numeric sySemi
{
iGlobalStackSize = (unsigned int)$3;
}
/* This semantic sets the SysCall flag for all API that follow.
* The Syscall determines if ES is saved or not.
*/
| sySysCall syEqual Boolean sySemi
{
fGlobalSysCall = $3;
}
/* This semantic sets the inline code generation flag to true or false.
* This flag is used to determine whether the compiler favors code size
* or execution speed when generating code.
*/
| syInline syEqual Boolean sySemi
{
fGlobalInline = $3;
}
/* Truncation enables/disables truncation checking when converting from
* a long value to a short value.
*
*/
| syTruncation syEqual Boolean sySemi
{
fGlobalTruncation = ($3) ? SEMANTIC_TRUNC : 0;
}
/* This semantic sets the flag to automatically generate map directives.
* If TRUE, a 16=>32 thunk will be generated for each mapping.
*
*/
| syEnableMapDirect1632 syEqual Boolean sySemi
{
fEnableMapDirect1632 = $3;
}
;
/******************************************************************************/
/******************************************************************************/
/* A mapping directive tells the compiler to generate a thunk in FROM
* the first ident, TO the second ident. For example, Foo => Foo32 would
* generate a thunk such that if an App called Foo, the thunk would
* convert all parameters and call Foo32 on the App's behalf.
*
* For a mapping to be valid, both names must have been declared in
* the same mapping declaration (Mapping)
*/
MapDirect : syIdent syMapDirect syIdent sySemi
{
{ /* Map Direct Block */
FunctionNode *temp1=NULL, *temp2=NULL;
/* Find both identifiers in the FunctionTable. If they map to each other,
* and they don't already exist in the MapTable,
* then create a mapping node in the MapTable to include them for code
* generation.
*/
if((temp1 = sym_FindSymbolFunctionNode(FunctionTable,$1))&&
(temp2 = sym_FindSymbolFunctionNode(FunctionTable,$3))){
if((temp1->pMapsToFunction == temp2) &&
(temp2->pMapsToFunction == temp1)) {
if(sym_FindFMapping(MapTable,$1,$3)) {
error("A mapping %s <=> %s already defined",$1,$3);
} else {
sym_AddFMapping(&MapTable,temp1,temp2);
}
} else {
error("%s does not map to %s",$1,$3);
}
} else {
error("Function %s undefined",(temp1) ? $3:$1);
}
} /* Map Direct Block */
}
;
/******************************************************************************/
/******************************************************************************/
/* A mapping defines the relationship between two Function declarations,
* and also relates the semantic operations to the parameters passed
* in the Function Mapping.
*/
Mapping : FunctionMap SemanticOps
{
/* Ensure that the same functions cannot be given other semantics.
* MapF1 and MapF2 are two global variables set when the FunctionMap is
* evaluated, and used by the SemanticOps rule. By the time we reach here,
* both are evaluated, and done with.
*/
MapF1 = MapF2 = NULL;
}
;
/******************************************************************************/
/******************************************************************************/
FunctionMap : FunctionDecl syEqual FunctionDecl
{
/* The thunk language does not require that the API types be declared.
* If no specific declaration is made, then the first API is assumed to
* be API16, and the second API32.
*
* Check to see if either API type was undeclared. If one was missing, insure
* that the other was also missing. If not, generate an error.
*
* If they were both missing, then default the first to be API16 and the
* second to be API32.
*/
if(($1->iCallType < 0) || ($3->iCallType < 0)) {
if(($1->iCallType < 0) && ($3->iCallType < 0)) {
$1->iCallType = TYPE_API16;
$3->iCallType = TYPE_API32;
} else {
error("Mapping missing an API type: %s = %s",
$1->pchFunctionName,$3->pchFunctionName);
}
}
/* Now check to see if the functions have already been declared. If so,
* then error. You may only define a function mapping once in this language.
*/
if(sym_FindSymbolFunctionNode(FunctionTable,$3->pchFunctionName)) {
error("%s already defined",$3->pchFunctionName);
} else {
if(sym_FindSymbolFunctionNode(FunctionTable,$1->pchFunctionName)) {
error("%s already defined",$1->pchFunctionName);
} else {
/* If both functions were missing from FunctionTable, then enter them into
* the FunctionTable, and set them so they map to each other.
*/
sym_InsertFunctionNode(&FunctionTable,$3);
sym_InsertFunctionNode(&FunctionTable,$1);
$1->pMapsToFunction = $3;
$3->pMapsToFunction = $1;
MapF1 = $1;
MapF2 = $3;
/* At this point, walk the list of parameters, and fixup pointers that
* have not been declared as a specific type, and any other parameters
* that are currently undetermined. Also, insure that all
* types can be converted between the two API.
*/
typ_FunctionsCanMap(MapF1,MapF2);
}
}
}
;
/******************************************************************************/
/******************************************************************************/
/* SemanticOps are found between curly braces at the end of a
* Mapping declaration. These semantic operations are LOCAL to the two
* functions, and have no effect on other mappings.
*/
SemanticOps : syLBrace SemanticOpList syRBrace
{
/**
** Check to ensure that semantics make sense
**/
/* skip it
if(typ_CheckSemantics(MapF1->ParamList,MapF2->ParamList))
error("Semantic error in %s<=>%s",
MapF1->pchFunctionName,MapF2->pchFunctionName);
*/
}
SemanticOpList : /* Empty Semantics */
| SemanticOpList SemanticOp sySemi
;
SemanticOp : syIdent syEqual syInOut
{
/* This semantic is basically the same for all, except it will set a
* different semantic flag.
*
* First, MapF1 must be non NULL. This implies that MapF2 is also non NULL.
* MapF1 points to the first function, and MapF2 points to the second.
*/
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
/* Here we search the parameter lists of both functions, looking for the
* first symbol name that matches the identifier given. T1 and T2 will
* end up pointing to the matching pair of parameters.
*
* This semantic is only valid for pointer parameters.
*/
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T1,&T2,$1)) {
if(T1->iPointerType && T2->iPointerType) {
if(T1->iBaseType == TYPE_STRING) {
/* Null terminated strings are input only */
error("Strings cannot be inout parameters");
} else {
/*
* Setting the INOUT semantic turns on both the INPUT and OUTPUT flags.
*/
T1->fSemantics =T1->fSemantics | SEMANTIC_INOUT;
T2->fSemantics =T2->fSemantics | SEMANTIC_INOUT;
}
} else {
error("Semantic invalid for non-pointer parameters");
}
} else {
error("%s not in parameter list of %s",
$1,MapF1->pchFunctionName);
}
}
}
| syErrNoMem syEqual Numeric
{
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
MapF1->ulErrNoMem = $3;
MapF2->ulErrNoMem = $3;
}
}
| syErrBadParam syEqual Numeric
{
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
MapF1->ulErrBadParam = $3;
MapF2->ulErrBadParam = $3;
}
}
| syErrUnknown syEqual Numeric
{
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
MapF1->fErrUnknown = 1;
MapF2->fErrUnknown = 1;
MapF1->ulErrUnknown = $3;
MapF2->ulErrUnknown = $3;
}
}
| syIdent syEqual syInput
{
/* Basically the same as syInout, except for semantic set is INPUT */
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T1,&T2,$1)) {
if(T1->iPointerType && T2->iPointerType) {
T1->fSemantics =(T1->fSemantics | SEMANTIC_INPUT)
& (~SEMANTIC_OUTPUT);
T2->fSemantics =(T2->fSemantics | SEMANTIC_INPUT)
& (~SEMANTIC_OUTPUT);
} else {
error("Semantic invalid for non-pointer parameters");
}
} else {
error("%s not in parameter list of %s",
$1,MapF1->pchFunctionName);
}
}
}
| syIdent syEqual syOutput
{
/* Basically the same as syInout, except for semantic set is OUTPUT */
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T1,&T2,$1)) {
if(T1->iPointerType && T2->iPointerType) {
if(T1->iBaseType == TYPE_STRING) {
error("Strings cannot be output parameters");
} else {
T1->fSemantics =(T1->fSemantics | SEMANTIC_OUTPUT)
& (~SEMANTIC_INPUT);
T2->fSemantics =(T2->fSemantics | SEMANTIC_OUTPUT)
& (~SEMANTIC_INPUT);
}
} else {
error("Semantic invalid for non-pointer parameters");
}
} else {
error("%s not in parameter list of %s",
$1,MapF1->pchFunctionName);
}
}
}
| syIdent syEqual sySizeOf syIdent
{
/* The Sizeof semantic declares the first syIdent to be the semantic size
* of the second syIdent. This size is determined at runtime of the thunk.
*
* Here, we must find both syIdent's in the parameter lists.
*/
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T1,&T2,$1)) {
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T3,&T4,$4)) {
if(T4->iBaseType == TYPE_STRING) {
error("Strings have no length semantics");
} else if(T1->iBaseType >= TYPE_CONV) {
error("Type of '%s' cannot represent length",$1);
} else if(T3->iPointerType == 0) {
error("Non pointer types have no length semantics");
} else {
/** Here, we relate the parameter to its size, and vice versa **/
if(T3->iBaseType == TYPE_STRUCT) {
if(typ_StructHasPointers(T3->pStructElems,T4->pStructElems))
error("sizeof on struct with imbedded pointers");
}
T1->fSemantics = T1->fSemantics | SEMANTIC_SIZE;
T2->fSemantics = T2->fSemantics | SEMANTIC_SIZE;
T3->pSizeParam = T1;
T4->pSizeParam = T2;
T1->pParamSizeOf = T3;
T2->pParamSizeOf = T4;
}
} else{
error("%s not in parameter list of %s",
$4,MapF1->pchFunctionName);
}
} else {
error("%s not in parameter list of %s",
$1,MapF1->pchFunctionName);
}
}
}
| syIdent syEqual syCountOf syIdent
{
/** This is basically the same as sySizeOf, except the semantic set is
* different
*/
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T1,&T2,$1)) {
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T3,&T4,$4)) {
if(T1->iBaseType == TYPE_STRING) {
error("Strings have no count semantics");
} else if(T1->iBaseType >= TYPE_CONV) {
error("Type of '%s' cannot represent count",$1);
} else if(T3->iPointerType == 0) {
error("Non pointer types have no count semantics");
} else if(T3->iBaseType == TYPE_STRUCT &&
typ_StructHasPointers(T3->pStructElems,
T4->pStructElems)) {
error("Countof on struct with imbedded pointers");
} else {
T1->fSemantics = T1->fSemantics | SEMANTIC_COUNT;
T2->fSemantics = T2->fSemantics | SEMANTIC_COUNT;
T3->pSizeParam = T1;
T4->pSizeParam = T2;
T1->pParamSizeOf = T3;
T2->pParamSizeOf = T4;
}
} else{
error("%s not in parameter list of %s",
$4,MapF1->pchFunctionName);
}
} else {
error("%s not in parameter list of %s",
$1,MapF1->pchFunctionName);
}
}
}
| syIdent syEqual syPassIfHiNull
{
/* Here, we mark a parameter to be passed through without conversion
* if its high word is null.
*/
if( !MapF1) {
error( "No mapping statement for semantic block");
} else {
if( sym_FindSymbolTypeNodePair( MapF1->ParamList,
MapF2->ParamList, &T1, &T2, $1)) {
if( T1->iPointerType && T2->iPointerType) {
T1->fSemantics |= SEMANTIC_PASSIFHINULL;
T2->fSemantics |= SEMANTIC_PASSIFHINULL;
} else {
error( "%s must be pointer to pass if hi null",
$1);
}
} else {
error( "%s not in parameter list of %s",
$1, MapF1->pchFunctionName);
}
}
}
| syIdent syEqual sySpecial
{
/* Here, we mark a parameter as needing special code.
*/
if( !MapF1) {
error( "No mapping statement for semantic block");
} else {
if( sym_FindSymbolTypeNodePair( MapF1->ParamList,
MapF2->ParamList, &T1, &T2, $1)) {
T1->fSemantics |= SEMANTIC_SPECIAL;
T2->fSemantics |= SEMANTIC_SPECIAL;
} else {
error( "%s not in parameter list of %s",
$1, MapF1->pchFunctionName);
}
}
}
| syIdent syEqual syMapToRetval RCCondition
{
/* Here, we mark a parameter to map to the return value of the other API.
*/
if( !MapF1) {
error( "No mapping statement for semantic block");
} else {
if( sym_FindSymbolTypeNodePair( MapF1->ParamList,
MapF2->ParamList, &T1, &T2, $1)) {
if( (MapF1->iCallType==TYPE_API16) &&
(T2->iBaseType==TYPE_STRUCT) &&
(T2->iPointerType)) {
T2->fSemantics |= SEMANTIC_MAPTORETVAL | $4;
} else if( (MapF2->iCallType==TYPE_API16) &&
(T1->iBaseType==TYPE_STRUCT) &&
(T1->iPointerType)) {
T1->fSemantics |= SEMANTIC_MAPTORETVAL | $4;
} else {
error( "%s can't map to a return value", $1);
}
} else {
error( "%s not in parameter list of %s",
$1, MapF1->pchFunctionName);
}
}
}
| syIdent syEqual syLocalHeap
{
/* Here, we mark a parameter as being relative to the local heap.
* In 32-bit it is a flat address.
* In 16-bit it is relative to the base of the local heap segment.
*/
if( !MapF1) {
error( "No mapping statement for semantic block");
} else {
if( sym_FindSymbolTypeNodePair( MapF1->ParamList,
MapF2->ParamList, &T1, &T2, $1)) {
T1->fSemantics |= SEMANTIC_LOCALHEAP;
T2->fSemantics |= SEMANTIC_LOCALHEAP;
} else {
error( "%s not in parameter list of %s",
$1, MapF1->pchFunctionName);
}
}
}
| syStack syIdent syEqual Numeric
{
/* Here, we can set the stack size of an individual function. This new value
* This new value overwrites the default value in the function node.
*
* syIdent is the name of the function that this value is to be set on,
* and must be one of the functions that the current semantic block is
* defined in.
*/
if(MapF1 && !strcmp($2, MapF1->pchFunctionName)) {
MapF1->iMinStack = (unsigned int)$4;
} else if( MapF2 && !strcmp($2, MapF2->pchFunctionName)) {
MapF2->iMinStack = (unsigned int)$4;
} else {
error("%s is not in current mapping",$2);
}
}
| syInline syIdent syEqual Boolean
{
/* Here we set the inline flag. Same explanation as syStack */
if(MapF1 && !strcmp($2, MapF1->pchFunctionName)) {
MapF1->fInlineCode = $4;
} else if( MapF2 && !strcmp($2, MapF2->pchFunctionName)) {
MapF2->fInlineCode = $4;
} else {
error("%s is not in current mapping",$2);
}
}
| syIdent syEqual syConforming
{
/* Here we set the conforming flag. Same explanation as syStack */
if(MapF1 && !strcmp($1, MapF1->pchFunctionName)) {
MapF1->fConforming = TRUE;
} else if( MapF2 && !strcmp($1, MapF2->pchFunctionName)) {
MapF2->fConforming = TRUE;
} else {
error("%s is not valid in current mapping",$1);
}
}
| syIdent syEqual syAllow AllowValues
{
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T1,&T2,$1)) {
if(T1->AllowList)
error("Allow/Restrict list redefined");
T1->AllowList = $4;
T2->AllowList = $4;
} else {
error("%s not in parameter list of %s",
$1,MapF1->pchFunctionName);
}
}
}
| syIdent syEqual syRestrict AllowValues
{
if( ! MapF1) {
error("No mapping statement for semantic block");
} else {
if(sym_FindSymbolTypeNodePair(MapF1->ParamList,MapF2->ParamList,
&T1,&T2,$1)) {
if(T1->iPointerType || T2->iPointerType) {
error("restrict semantic invalid "
"for pointer parameters");
} else {
T1->fSemantics = T1->fSemantics | SEMANTIC_RESTRICT;
T2->fSemantics = T2->fSemantics | SEMANTIC_RESTRICT;
if(T1->AllowList)
error("Allow/Restrict list redefined");
T1->AllowList = $4;
T2->AllowList = $4;
}
} else {
error("%s not in parameter list of %s",
$1,MapF1->pchFunctionName);
}
}
}
;
/******************************************************************************/
/******************************************************************************/
/* A function declaration accepts a CallType, a return type, an identifier,
* and a list of parameters. It then makes a function node containing
* all of this information. If the CallType is not given, then the
* field is passed as undefined (-1), and will be determined later.
*/
FunctionDecl : CallType KnownType syIdent Parameters
{
$$ = typ_MakeFunctionNode($1,$2,$3,$4);
}
| KnownType syIdent Parameters
{
$$ = typ_MakeFunctionNode(-1,$1,$2,$3);
}
| CallType CallSemantics KnownType syIdent Parameters
{
$$ = typ_MakeFunctionNode($1,$3,$4,$5);
$$->ReturnType->fSemantics |= $2;
}
| CallSemantics KnownType syIdent Parameters
{
$$ = typ_MakeFunctionNode(-1,$2,$3,$4);
$$->ReturnType->fSemantics |= $1;
}
;
/******************************************************************************/
CallSemantics : syLocalHeap
{
$$ = SEMANTIC_LOCALHEAP;
}
| sySpecial
{
$$ = SEMANTIC_SPECIAL;
}
;
/******************************************************************************/
RCCondition : /* Empty */
{
$$ = 0;
}
| syReverseRC
{
$$ = SEMANTIC_REVERSERC;
}
;
/******************************************************************************/
/******************************************************************************/
/* The Allow list is a list of values that the compiler will truncate
* without returning an error. Such values are used when a parameter
* that is normally declared as a ULONG is passed around using
*
*/
AllowValues : syLParen AllowList syRParen
{
$$ = $2;
}
;
AllowList : /* Empty */
{
}
| Allow
{
$$ = $1;
}
| AllowList syComma Allow
{
if($$ = $3) {
$3->Next = $1;
}
}
;
Allow : Numeric
{
$$ = typ_MakeAllowNode($1);
}
;
/******************************************************************************/
/******************************************************************************/
/* Because of the way the yacc parser works, the list of parameters
* has been built in the reverse order of what the compiler needs.
* Therefore, we need to reverse the order of the list of types
* returned by ParamList
*/
Parameters : syLParen ParamList syRParen
{
$$ = sym_ReverseTypeList($2);
}
;
/* A parameter list is a comma separated list of ParamType
*/
ParamList : /* empty */
{
$$ = NULL;
}
| ParamType
{
$$ = $1;
}
| ParamList syComma ParamType
{
/* Check to see if the identifier for ParamType is already in the
* list ParamList. If so, it's an error.
*/
if($$ = $3) {
if( sym_FindSymbolTypeNode($1,typ_NonNull($3->pchIdent))) {
error("Duplicate Parameter : %s",$3->pchIdent);
} else {
$3->pNextNode = $1;
}
} else {
$$ = $1;
}
}
;
/* Param type is only used in formal parameter declarations.
* Here, we look for the next ParamDecl. If it is non-null, then
* we check it for a few conditions, and pass it back.
*/
ParamType : ParamDecl Reserved
{
if($$ = $1) {
$$->iDeleted = $2;
$$->iFillValue = iPushValue;
/*
* Structures can only be passed by pointer through an API
*/
/*
* if(($1->iBaseType == TYPE_STRUCT) && (!$1->iPointerType)) {
* error("Structure parameters require pointer type");
* }
*/
/*
* Array types can only be passed by pointer through an API
*/
if(($1->iArraySize > 1) && (!$1->iPointerType)) {
error("Array parameters require pointer type");
}
/*
* Void types must be pointers.
*/
if(($1->iBaseType == TYPE_VOID) && (!$1->iPointerType)) {
error("Void types must be pointers");
}
/*
* We currently don't handle arrays of structures.
*/
if(($1->iBaseType == TYPE_STRUCT) && ($1->iArraySize > 1)) {
error("Parameters cannot be arrays of structures");
}
}
}
;
Reserved : /** No reserved keyword **/
{
$$ = 0;
}
| syDeleted
{
$$ = TYPE_DELETED;
iPushValue = 0;
}
| syDeleted Numeric
{
$$ = TYPE_DELETED;
iPushValue = $2;
}
;
/******************************************************************************/
/******************************************************************************/
/* A TypeDecl handles typedef statements. A valid typedef statement must
* include a KnownType, and a new identifier, an optional ArrayDecl, and
* end with a semicolon.
*/
TypeDecl : KnownType syIdent ArrayDecl sySemi
{
/* If the 'KnowType' was not recogized, then an error message has already
* been issued, and we don't need further action
*/
if( !$1) {
$$ = NULL;
} else
/* Now, search for the syIdent in the currently known TypeTable. If it
* is found, then it is a redeclaration, which is not allowed.
*
* If not found, then make a copy of the TypeNode, and insert it into
* TypeTable.
*
* Check to see if the new type is a special handle. Set a flag if so.
*
* Then check the array size. If the array size > 1 already, then it's
* an error, since would redefine the size of the array.
*/
if( sym_FindSymbolTypeNode(TypeTable,$2)) {
error("Duplicate Declaration of %s",$2);
} else {
$$ = typ_CopyTypeNode($1);
if($$) {
$$->pchIdent = typ_DupString($2);
sym_InsertTypeNode(&TypeTable,$$);
typ_EvalHandleType( $$);
switch ($3) {
case -1 : break;
case 0 :
error("%s declared as array size = 0",$2);
break;
default :
if($$->iArraySize == 1) {
$$->iArraySize = $3;
} else if($3 < -1) {
error("%s declared array size < 0",$2);
} else {
error("%s redeclared array size",$2);
}
}
}
}
}
/* Structure definitions come in two flavors, one with an alignment
* declaration, and one without.
*
* The workings are exactly like the other typedef, except that arrays
* of structures are not allowed.
*/
| syStruct syIdent StructDef syIdent sySemi
{
if( $$ = $3) {
if( sym_FindSymbolTypeNode(TypeTable,$4)) {
error("Duplicate Declaration of %s",$4);
} else {
$$->iAlignment = -1;
$$->pchBaseTypeName =(char *)malloc(8+strlen($4));
sprintf($$->pchBaseTypeName,"struct %s",$4);
$$->pchIdent = (char *) typ_DupString($4);
sym_InsertTypeNode(&TypeTable,$$);
}
}
}
| Aligned syStruct syIdent StructDef syIdent sySemi
{
if( $$ = $4) {
if( sym_FindSymbolTypeNode(TypeTable,$5)) {
error("Duplicate Declaration of %s",$5);
} else {
$$->iAlignment = $1;
$$->pchBaseTypeName =(char *)malloc(8+strlen($5));
sprintf($$->pchBaseTypeName,"struct %s",$5);
$$->pchIdent = (char *) typ_DupString($5);
sym_InsertTypeNode(&TypeTable,$$);
}
}
}
;
/******************************************************************************/
/******************************************************************************/
/* A structure definition creates a type node, which has pStructElems that
* points to a list of typenodes. This list of typenodes consists of the
* elements of the structure.
*/
StructDef : syLBrace StructList syRBrace
{
if($2) {
$$ = typ_MakeTypeNode(TYPE_STRUCT);
$$->pStructElems = $2;
} else
$$ = NULL;
}
;
/*
* StructList makes a list of structure elements.
*/
StructList : /* empty */
{
$$ = NULL;
}
| StructElem StructList
{
if($$ = $1) {
if( sym_FindSymbolTypeNode($2,$1->pchIdent))
error("Duplicate Declaration of %s",$1->pchIdent);
$$->pNextNode = $2;
}
}
;
/* A structure element is declared the same way as a formal parameter
* is declared, minus the comma separators. Reuse that rule for a StructElem.
*/
StructElem : ParamDecl Reserved sySemi
{
if($$ = $1) {
$$->pNextNode = NULL;
$$->iFillValue = iPushValue;
$$->iDeleted = $2;
if( $$->iDeleted && $$->iPointerType) {
error("Deleted element %s cannot be pointer",
$$->pchIdent);
}
}
}
| ParamDecl StructSemantics sySemi
{
if($$ = $1) {
$$->pNextNode = NULL;
$$->iFillValue = 0;
$$->iDeleted = 0;
$$->fSemantics |= $2;
}
}
;
/******************************************************************************/
StructSemantics : syPassIfHiNull
{
$$ = SEMANTIC_PASSIFHINULL;
}
;
/******************************************************************************/
/******************************************************************************/
/* An array declaration is either non-existent, or is a number enclosed in
* brackets. Return the number in brackets, or -1 if it doesn't exist.
*/
ArrayDecl : /** No array Declaration **/
{
$$ = -1;
}
| syLBrack Numeric syRBrack
{
$$ = (int)$2;
}
;
/******************************************************************************/
/******************************************************************************/
/* ParamDecl is a rule used in the declaration of parameters, and is also
* used when declaring a structure. It will return a typenode, which has
* been filled out with all the given information. There are two types of
* ParamDecl. The first is the full definition, such as one would use in
* the definition of a structure element. The other is a short definition,
* such as in a function prototype. Both are legal, though the full
* definition is required to declare an array.
*/
ParamDecl : KnownType syIdent ArrayDecl
{
if($$ = $1) {
$$->pchIdent = typ_DupString($2);
switch ($3) {
case -1 : break;
case 0 : error("%s declared as array size = 0",$2);
break;
default :
if($$->iArraySize == 1) {
$$->iArraySize = $3;
} else if($3 < -1) {
error("%s declared array size < 0",$2);
} else {
error("%s redeclared array size",$2);
}
}
}
}
| KnownType
{
if($$ = $1)
$$->pchIdent = NULL;
}
;
/******************************************************************************/
/******************************************************************************/
/* The aligned statement matches an optional alignment keyword followed
* by the word 'aligned'. Used in the declaration and use of structures.
*/
Aligned : syDWord syAligned
{
$$ = 4;
}
| syWord syAligned
{
$$ = 2;
}
| syByte syAligned
{
$$ = 1;
}
| syDWord
{
$$ = 4;
}
| syWord
{
$$ = 2;
}
| syByte
{
$$ = 1;
}
;
/******************************************************************************/
/******************************************************************************/
/* A knowntype returns a pointer to a copy of a known type. A known type is
* one that is built into the language, or one that has been declared using
* a typedef. Note that it will always return a COPY of the item. This allows
* the rest of the compiler to change the fields in the typenode, without
* changing other uses of the same typenode.
*
* It is possible for a known type to be required to be a pointer.
* If an item must be a pointer type, such as a string, checking is done
* here, by using the ExtendedBaseType rule. Anything using the Extended
* BaseType is supposed to have a pointer operator with it, such as the
* case where the type is a string.
*
*/
KnownType : ExtendedBaseType PointerDecl
{
if( $1) {
$$ = typ_CopyTypeNode($1);
if($2)
$$->iPointerType = $2;
else
error("Type must be pointer");
}
}
| BaseType PointerDecl
{
if( $1) {
$$ = typ_CopyTypeNode($1);
if($2)
$$->iPointerType = $2;
}
}
| Aligned BaseType PointerDecl
{
if( $$ = $2) {
if( $2->iBaseType == TYPE_STRUCT) {
$$ = typ_CopyTypeNode($2);
$$->iAlignment = $1;
if( $3)
$$->iPointerType = $3;
} else {
error("Alignment only applies to structures");
}
}
}
/* | Aligned BaseType PointerDecl
{
if( $$ = $2) {
$$ = typ_CopyTypeNode( $2);
if( $3)
$$->iPointerType = $3;
$$->iAlignment = $1;
if( ($2->iBaseType != TYPE_STRUCT) && ($1 != -1)) {
error( "Alignment only applies to structures");
}
}
}
*/
;
/******************************************************************************/
/******************************************************************************/
/** Extended base types determine types which are pointers */
/** An Extended base type is different in that it requires a pointer **/
ExtendedBaseType : syString
{
$$ = BaseTable[SYMTAB_STRING];
}
;
/* BaseType is a rule that is the bottom of the type search tree. Here,
* the compiler either finds the type being looked for, or reports an
* error. If the type is a 'built-in' type, then a pointer to the item
* in the BaseTable is returned, without searching the list of types.
*
* Otherwise, the symbol found is a syIdent, which will be used to search
* the TypeTable. If the TypeTable contains the syIdent, then it is a
* known type, and a pointer to it will be returned. Otherwise, it is an
* undefined type, and an error is reported.
*/
BaseType : syLong
{
$$ = BaseTable[SYMTAB_LONG];
}
| syShort
{
$$ = BaseTable[SYMTAB_SHORT];
}
| syInt
{
$$ = BaseTable[SYMTAB_INT];
}
| syUnsigned syLong
{
$$ = BaseTable[SYMTAB_ULONG];
}
| syUnsigned syShort
{
$$ = BaseTable[SYMTAB_USHORT];
}
| syUnsigned syInt
{
$$ = BaseTable[SYMTAB_UINT];
}
| syVoid
{
$$ = BaseTable[SYMTAB_VOID];
}
| syUnsigned syChar
{
$$ = BaseTable[SYMTAB_UCHAR];
}
| syChar
{
$$ = BaseTable[SYMTAB_CHAR];
}
| syIdent
{
$$ = sym_FindSymbolTypeNode(TypeTable,$1);
if( $$ == NULL)
error("type '%s' unknown",$1);
}
| syNullType
{
$$ = BaseTable[SYMTAB_NULLTYPE];
}
;
/******************************************************************************/
/******************************************************************************/
/* There are Four types of pointer declarations. None, in which case a
* zero is returned. A syPtr, or '*', which defines an unspecified pointer
* type. A syNear32 and syFar16 define specific pointer types, which are
* special.
*/
PointerDecl : /** No pointer decl **/
{
$$ = 0;
}
| syPtr
{
$$ = TYPE_PTR;
}
| syFar16
{
$$ = TYPE_FAR16;
}
| syNear32
{
$$ = TYPE_NEAR32;
}
;
/******************************************************************************/
/******************************************************************************/
CallType : syAPI16
{
$$ = TYPE_API16 ;
}
| syAPI32
{
$$ = TYPE_API32;
}
;
/******************************************************************************/
/******************************************************************************/
Boolean : syTrue
{
$$ = TRUE;
}
| syFalse
{
$$ = FALSE;
}
;
/******************************************************************************/
/******************************************************************************/
Numeric : syNumber
{
$$ = $1;
}
| Numeric syPlus Numeric
{
$$ = $1 + $3;
}
| Numeric syMinus Numeric
{
$$ = $1 - $3;
}
| Numeric syPtr Numeric /** syPtr = '*' **/
{
$$ = $1 * $3;
}
| Numeric syDiv Numeric
{
if($3)
$$ = $1 / $3;
else
error("Divide by zero");
}
;
/******************************************************************************/
/******************************************************************************/
%%
extern int yydebug;
void yyerror(s)
char *s;
{
error(s);
}