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.
912 lines
32 KiB
912 lines
32 KiB
notes:
|
|
|
|
identify functions that can be used in both
|
|
user mode and km to perform
|
|
memory mapped file read, write
|
|
memory allocation
|
|
what is memory scheme used by NT?
|
|
how do you realloc memory and still retain
|
|
the same starting address if all memory segments share
|
|
the linear address space?
|
|
|
|
use HeapAlloc? Cannot use virtualalloc()
|
|
|
|
just so I can start writing code assume:
|
|
|
|
base_pointer = VirtualAlloc(NULL, max_size_in_bytes, MEM_RESERVE,
|
|
PAGE_NOACCESS) ;
|
|
pointer = VirtualAlloc(base_pointer, size_needed_in_bytes, MEM_COMMIT,
|
|
PAGE_READWRITE) ;
|
|
as you need more memory, just commit more and more until
|
|
max_size is reached.
|
|
VirtualFree(pointer)
|
|
|
|
Set up build env to create dll, make file, dependencies
|
|
etc.
|
|
|
|
----
|
|
typedef struct
|
|
{
|
|
} GPD, *PGPD; // structure containing raw GPD data
|
|
|
|
/* ----
|
|
* new prefixes:
|
|
* gpd: a GPD structure
|
|
* pgpd: ptr to GPD structure
|
|
*/
|
|
|
|
|
|
allocate memory for all scaffold structures.
|
|
Allocate more memory than the structure will need since
|
|
reallocation may be impossible. All structures may be
|
|
carved from one gigantic block of memory.
|
|
|
|
Initialize a master table to keep track of all structures.
|
|
The master table is an array of entries of the form:
|
|
|
|
struct _MASTER_TABLE_ENTRY
|
|
{
|
|
PBYTE pubStruct ; // address of element zero of array
|
|
DWORD dwArraySize ; // number of elements that can fit into memory
|
|
// set to MAX_SYMBOLNODES for [SYMBOLTREE]
|
|
DWORD dwCurIndex ; // points to first uninitialized element
|
|
DWORD dwElementSiz ; // size of each element in array.
|
|
} MASTERTABENTRY ;
|
|
|
|
all offsets are to each individual array. There is no
|
|
master offset.
|
|
|
|
MASTERTAB_ENTRY gMasterTable[MTI_MAX_ENTRIES] ;
|
|
|
|
Bufffers needed for:
|
|
|
|
typedef enum
|
|
{
|
|
MTI_SOURCEBUFFER: Source file (GPD input stream)
|
|
not sure how memory mapped files and recursive includes
|
|
will alter this.
|
|
MTI_STRINGHEAP: String heap
|
|
MTI_TOKENMAP: tokenMap large enough to hold an old and New copy!
|
|
MTI_NEWTOKENMAP: newtokenMap (not a separate buffer from TOKENMAP -
|
|
just points immediately after oldTokenMap).
|
|
MTI_SYMBOLTREE: symbolTree Array
|
|
MTI_BLOCKMACROARRAY (one for Block and another for Value macros)
|
|
MTI_DFEATURE_OPTIONS: references a whole bunch of treeroots.
|
|
should be initialized to ATTRIB_UNINITIALIZED values.
|
|
SymbolID pointed to by dwFeatureSymbols contains largest
|
|
array index appropriated. We won't need to allocate
|
|
more elements in the final array than this.
|
|
MTI_TTFONTSUBTABLE: array of arrayrefs and integers.
|
|
MTI_GLOBALATTRIB: structure holding value of global attributes.
|
|
MTI_ATTRIBTREE: array of ATTRIB_TREE structures.
|
|
MTI_COMMANDTABLE: array of PATREEREF (or DWORD indicies to COMMAND_ARRAY)
|
|
// the size of this table is set by the number of
|
|
// predefined Unidrv commands.
|
|
MTI_COMMANDARRAY: array of COMMAND structures.
|
|
// size varies depending on number of commands and variants
|
|
// defined in the GPD file.
|
|
MTI_FONTCART: array of FontCartridge structures - one per construct.
|
|
MTI_LISTNODES: array of LISTNODEs.
|
|
MTI_MAX_ENTRIES: Last entry.
|
|
} MT_INDICIES ;
|
|
|
|
|
|
Note: the prefix MTI_ stands for MasterTableIndex, the
|
|
base portion of the name is the structure typedef.
|
|
|
|
BLOCKMACROARRAY is an array of structs temporarily carved into
|
|
a buffer:
|
|
typedef struct
|
|
{
|
|
DWORD tIndexID; tokenindex where a macro ID value is stored
|
|
DWORD tIndexOpen; index of open brace
|
|
DWORD tIndexClose; index of closing brace
|
|
} BLOCKMACROARRAY ;
|
|
|
|
|
|
|
|
each dword contains the tokenIndex where a macro ID value is stored.
|
|
curBlockMacroArray points to the smallest index of the macroArray currently
|
|
uninitialized. (initially curBlockMacroArray = 0)
|
|
|
|
VALUEMACROARRAY is an array of DWORDS holding a
|
|
tokenindex where a valuemacro ID value is stored
|
|
|
|
MACROLEVELSTACK: is operated as a two dword stack that saves the
|
|
values of curBlockMacroArray and curValueMacroArray , each time
|
|
a brace is encountered.
|
|
|
|
-------
|
|
|
|
increaseMacroLevel(): called in response to parsing open brace.
|
|
Copy this entry to the newtokenarray .
|
|
save the value of curBlockMacroArray and curValueMacroArray in the
|
|
macrolevelstack. we will use this later.
|
|
check if this brace begins the definition of a blockmacro,
|
|
this is easy to do.
|
|
if( curBlockMacroArray &&
|
|
(BlockMacroArray[curBlockMacroArray - 1].tIndexOpen == -1))
|
|
{
|
|
yes, we are beginning a BlockMacro definition.
|
|
record newtokenArray index of open brace entry in tIndexOpen.
|
|
check to see tIndexOpen is one higher than tIndexID, else
|
|
a syntax error needs to be flagged for this blockMacro.
|
|
}
|
|
|
|
decreaseMacroLevel: called in response to parsing close brace.
|
|
temporarily save curBlockMacroArray and curValueMacroArray
|
|
into temp vars largerBlockIndex and largerValueIndex.
|
|
|
|
now pop the value of curBlockMacroArray and curValueMacroArray from the
|
|
stack.
|
|
locate all macros referenced in the macroarray (less than largerIndex,
|
|
and greater than or equal to curMacroArray retrieved from stack)
|
|
that are expired due to the change in level. Delete their entries
|
|
in the tokenmap by replacing their tkKeyID by NULLKEY. This
|
|
will break the endless chain resulting when a macro defines another
|
|
macro.
|
|
|
|
Does this closing brace end a macro definition?
|
|
if(MacroArray[curMacroArray - 1].tIndexClose == -1) //yes
|
|
{
|
|
MacroArray[curMacroArray - 1].tIndexClose =
|
|
location of } in newtokenArray;
|
|
}
|
|
Copy this entry to the newtokenarray .
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
|
|
The symbol tree is comprised of these nodes. The symbol tree
|
|
organizes the symbol space into a hierarchy. For each feature
|
|
symbol, there is a set of option symbols particular to that feature.
|
|
All symbol nodes are stored in one array. Multiple trees may
|
|
exist in one array. When the symboltree is frozen, it can be
|
|
optimized by restoring the tree as an array of (STRREFs+subSpaceIndex.
|
|
Where the symbolID serves as the index to the arrayref.
|
|
(+ symboltype offset) The end of each symbol list may be signified by
|
|
a NULL arrayref.
|
|
|
|
|
|
typedef struct
|
|
{
|
|
ARRAYREF arSymbolName;
|
|
DWORD dwSymbolID; // has nothing to do with array of symbol structs.
|
|
// value begins at zero and is incremented to obtain
|
|
// next value.
|
|
DWORD dwNextSymbol; // index to next element in this space.
|
|
DWORD dwSubSpaceIndex ; // index to first element in new symbol space
|
|
which exists within the catagory represented by this symbol.
|
|
for example in the catagory represented by the
|
|
symbol PAPERSIZES: we may have the subspace
|
|
comprised of Letter, A4, Legal, etc.
|
|
} SYMBOLNODE , * PSYMBOLNODE ;
|
|
// assign this struct the type 'psn'
|
|
|
|
|
|
// ---- Global and state Variables ---- //
|
|
{
|
|
// ---- Index in SYMBOLNODE array to each type of tree ---- //
|
|
|
|
DWORD gdwFeatureSymbols ; // initially set to INVALID_INDEX
|
|
DWORD gdwFontCartSymbols ;
|
|
DWORD gdwTTFontSymbols ;
|
|
DWORD gdwBlockMacroSymbols ;
|
|
DWORD gdwValueMacroSymbols ;
|
|
|
|
// ---- track value of curBlockMacroArray and curValueMacroArray ---- //
|
|
|
|
DWORD gdwCurBlockMacroArray ; // initially set to zero. First
|
|
DWORD gdwCurValueMacroArray ; // writable slot in MacroArray.
|
|
DWORD gdwMacroLevelStackPtr ; // Push: write values into
|
|
// MacroLevelStack[MacroLevelStackPtr++]
|
|
// Pop: read values from
|
|
// MacroLevelStack[--MacroLevelStackPtr]
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct _TOKENMAP
|
|
{
|
|
DWORD dwKeywordID ; // index of entry in KeywordTable
|
|
ABSARRAYREF aarKeyword ; // points to keyword in the source file
|
|
ABSARRAYREF aarValue ; // value associated with this keyword.
|
|
// an arrayref is needed if we store
|
|
// the value in the heap.
|
|
// It also makes copying the string
|
|
// to another place easier. No need to
|
|
// search for a linebreak char. Just
|
|
// Copyn() will do.
|
|
DWORD dwValue ; // interpretation of Value string - see flags.
|
|
// maybe commandID, numerical value of constant, MacroID assigned
|
|
// to MacroSymbol , SymbolID etc.
|
|
|
|
DWFLAGS dwFlags ; // bitfield with the following flags
|
|
// TKMF_VALUE_SAVED independently of the tokenmap.
|
|
// TKMF_COMMAND_SHORTCUT only used when parsing commands.
|
|
// TKMF_INLINE_BLOCKMACROREF need to know when resolving macros.
|
|
// TKMF_MACROREF indicates a value macro reference that must be resolved
|
|
// TKMF_SYMBOLID dwValue contains a symbolID.
|
|
// TKMF_SYMBOL_REGISTERED set when the symbolID is registered.
|
|
// TKMF_EXTERN: The extern Qualifier was prepended to the keyword
|
|
// and has now been truncated.
|
|
|
|
} TKMAP, *PTKMAP
|
|
|
|
special keywordIDs:
|
|
|
|
ID_NULLENTRY: ignore this, either expired code, parsing error etc.
|
|
ID_UNRECOGNIZED: conforms to correct syntax, but not in my keyword table.
|
|
could be a keyword defined in a newer spec or name of valuemacro.
|
|
other other OEM defined stuff.
|
|
ID_SYMBOL: does not begin with * , but conforms to syntax
|
|
for a symbol.
|
|
ID_EOF: end of file - no more tokenMap entries
|
|
|
|
-----------------------------------
|
|
|
|
During the parsing to create the token map we
|
|
a) replace all comments with spaces
|
|
b) replace consecutive linebreaks with spaces.
|
|
c) parse all mainkeywords and replace with keywordIDs
|
|
d) init pointers to keywords and arrayref to values
|
|
e) set appropriate flags.
|
|
f) register symbols.
|
|
|
|
|
|
// ---- note ---- //
|
|
all functions parsing the input stream may indicate
|
|
reaching EOB by returning NULL. caller should check for
|
|
NULL return value after calling these functions and
|
|
react accordingly.
|
|
// -------------- //
|
|
|
|
BUG_BUG: CreateTokenMap should note if
|
|
*Command is the short version. If so
|
|
then 2nd pass (macroresolution) should
|
|
expand it so special case code is not needed.
|
|
|
|
PTKMAP CreateTokenMap(
|
|
IN OUT PBYTE pubCur // location within source to start parsing
|
|
)
|
|
{
|
|
PBYTE pubNewPos ; // transient data.
|
|
|
|
// assume we are at parsing level 0 - outside of any
|
|
// contexts requiring a change of parsing rules.
|
|
|
|
pubCur = PubEatWhite(pubCur) ;
|
|
|
|
this function will move forward until the first non-whitespace
|
|
or non-linebreak character is encountered. Convert first
|
|
occurances of consecutive linebreak chars to whitespace.
|
|
(should this be done here?: convert linebreak+continuation
|
|
to whitespace.)
|
|
|
|
/* PubEatComments(pubCur) */
|
|
|
|
if pubCur points to start of a valid comment, this function
|
|
will advance until linebreak character is encountered.
|
|
it will also completely consume the comment by replacing
|
|
all the characters with spaces.
|
|
|
|
while((pubNewPos = PubEatComments(pubCur)) != pubCur)
|
|
{
|
|
pubCur = pubNewPos ;
|
|
pubCur = PubEatWhite(pubCur) ;
|
|
}
|
|
|
|
at this point pubCur points to first non-WHITE char that
|
|
is also not a comment.
|
|
|
|
we expect to see {, } (braces) or a valid keyword at this
|
|
point.
|
|
|
|
while(pubCur)
|
|
{
|
|
pubCur = dwIdentifyKeyword(pubCur, tkmap+i) ;
|
|
|
|
|
|
this function does several things:
|
|
'brackets' keyword to see if it is properly terminated with :
|
|
and begins with * (if it is not a brace).
|
|
performs table lookup to obtain the keywordID which is written
|
|
to tkmap[i].dwKeywordID .
|
|
Determines based on the keyword ID if next token represents
|
|
another keyword (as is the case if keyword is a brace)
|
|
or if it represents a value. If its a keyword, assigns NULL
|
|
to arValue, else arValue points to first nonwhite char
|
|
in value after the : delimiter. This function treats
|
|
the value as a black box.
|
|
If the keyword happens to be a brace, dwValue
|
|
will hold the nesting level of the brace.
|
|
This will allow very fast identification of scope.
|
|
|
|
If the state machine is used at this point we can
|
|
resolve attribute names. Otherwise we scan only
|
|
for non-attribute keywords and mark all other legally
|
|
constructed keywords as UNRECOGNIZED. However attributes
|
|
prefaced with EXTERN_FEATURE or EXTERN_GLOBAL may be
|
|
identified at this time.
|
|
|
|
A second pass using the state machine then applies the
|
|
proper attribute namespace and resolves all UNRECOGNIZED
|
|
keywords. All remaining unrecognized keywords produce
|
|
a warning message.
|
|
|
|
Returns pubCur, which points to first char in the value or
|
|
first char of next keyword if no value exists.
|
|
|
|
Error handling: calls a function WriteErrorMsg() to
|
|
record any errors that it encounters. may set dwKeywordID
|
|
to ERROR, and set pubValue pointing to offending keyword,
|
|
and return this value in pubCur.
|
|
|
|
pubCur = scanOverValue(pubCur) ;
|
|
init arValue, set dwFlags.
|
|
Note: lets parse the value only to reach the next
|
|
keyword, not with the intent of saving the value
|
|
somewhere. This is because at this point we have
|
|
no clue as to where the value should be
|
|
saved to. Wait for a subsequent pass to avoid
|
|
cluttering the heap with data that will eventually
|
|
be cubbyholed elsewhere. There are a few execptions
|
|
that will cause things to happen. One is if the shortcut
|
|
version of another construct is encountered, then
|
|
we must expand this in the tokenMap so it looks like
|
|
the full fledged version. On the other hand we may
|
|
choose to defer the expansion till later, but we
|
|
may flag this now.
|
|
See *command for an example.
|
|
|
|
Also replace any occurances of linebreak + continuation
|
|
char with spaces.
|
|
|
|
Eat comments and white spaces until we reach beginning of
|
|
a non-Null statement.
|
|
}
|
|
|
|
things that need to be done at some point
|
|
in this function:
|
|
|
|
lazy way to guard against useage of command shortcuts:
|
|
when ever encountering a command keyword, leave
|
|
the following entry unused. (mark it as NULL keyword)
|
|
|
|
the Command name (the value portion)
|
|
needs to be parsed and converted to a unidrv ID
|
|
this may be placed in tokenmap.dwValue.
|
|
set the flag TKMF_SYMBOL_REGISTERED. This will
|
|
prevent the value string from getting registered in a
|
|
symbol table.
|
|
}
|
|
|
|
|
|
defineAndResolveMacros()
|
|
this function scans through the tokenMap
|
|
making a copy of the tokenMap without
|
|
the macrodefinitions or references. All references
|
|
are replaced by the definitions inserted in-line!
|
|
|
|
|
|
{
|
|
Can't store ValueMacro Definitions in scratch memory, they
|
|
will actually be referenced directly if the value is not
|
|
a string!
|
|
|
|
initialize NEWTOKENMAP to refer to unused entries
|
|
in TOKENMAP buffer. We will create a new copy of
|
|
the tokenmap here!
|
|
|
|
1st pass:
|
|
defineBlockMacroSymbols()
|
|
search for all *BlockMacro keywords
|
|
add macro symbol definitions
|
|
to the symbol tree. assign them
|
|
an ordinal ID value 1, 2, 3, ...
|
|
in this case, we may use the tree
|
|
as a pure array of StringRefs. with
|
|
in index to the first uninitialized entry.
|
|
write the macroID value into the tokenMap.dwValue.
|
|
|
|
ScanForMacroReferences();
|
|
|
|
walk through the old tokenMap one entry at a time.
|
|
|
|
for (every entry in the tokenMap)
|
|
{
|
|
switch()
|
|
{
|
|
case (entry begins a block macrodef)
|
|
copy token entry into new tokenMap
|
|
record the new tokenIndex into
|
|
BlockMacroArray[curBlockMacroArray]
|
|
set tIndexOpen and close to -1 to indicate
|
|
not yet initialized.
|
|
increment curBlockMacroArray.
|
|
(all lines of macrodef are automatically copied over!)
|
|
case (entry contains a block macroref)
|
|
convert the symbolname to a macroID via
|
|
the symboltree. Search the BlockMacroArray entries
|
|
from index curBlockMacroArray - 1 to zero
|
|
using the first macroID that matches.
|
|
|
|
copy all the valid tokenMap entries
|
|
between BlockMacroArray[index].tIndexOpen
|
|
and tIndexClose defined for the block macro
|
|
referenced. Avoid circular reference by ensuring
|
|
tIndexClose != -1 for the selected macro.
|
|
|
|
case (entry begins a value macrodef: *Macros)
|
|
defineValueMacros()
|
|
|
|
case (entry references a valuemacro)
|
|
know by checking tokenMap.dwFlags = MACROREF.
|
|
dereferenceValueMacro()
|
|
// sorry, cannot defer this since value macros
|
|
// have a limited scope. We must access the
|
|
// valueMacroArray at the time we see the reference
|
|
// since valueMacroArray dynamically changes as we
|
|
// encounter braces.
|
|
|
|
case ({) increment macro nesting level
|
|
any macro defined within a macro is undefined
|
|
outside of that macro!
|
|
|
|
case (}) decrease macro nesting level.
|
|
|
|
default; // all other entries
|
|
copy to new tokenMap
|
|
}
|
|
}
|
|
old tokenMap is now useless, its memory now lies fallow.
|
|
}
|
|
|
|
ScanForMacroReferences()
|
|
{
|
|
may want to factor out common stuff.
|
|
|
|
for (each entry in oldTokenMap)
|
|
{
|
|
if(entry does not define an macro nor is a brace char)
|
|
{
|
|
must scan all values for macroReference.
|
|
if a non string value is expected, the = macroname
|
|
must be the first and only entity comprising the value.
|
|
If its a string, we must parse each construct!
|
|
set flag in oldTokenMap.
|
|
can share code used in defineValueMacros().
|
|
}
|
|
}
|
|
}
|
|
|
|
// note: all continuation chars have been replaced by spaces
|
|
// previously at scanOverValue() time.
|
|
|
|
defineValueMacros(old, newtokenindex)
|
|
{
|
|
this function is called upon encountering
|
|
a *Macros: groupname construct
|
|
|
|
check to see there is an opening brace
|
|
|
|
while(tokenArray[tokenindex].keywordID != closingBrace)
|
|
{
|
|
each entry up to the closing brace defines a
|
|
value macro.
|
|
|
|
register macroname in ValueMacroSymbols tree
|
|
Store index to tokenArray in
|
|
valueMacroArray
|
|
|
|
maybe also valueMacroArray should
|
|
have an arrayref
|
|
|
|
|
|
1) we have no idea what value is being defined or how
|
|
to properly parse for it.
|
|
the value may reference another macro(s)
|
|
|
|
so the only time we attempt parsing the value is
|
|
if the value appears to be a string macro. If at any time
|
|
the parsing fails, the entire value is treated as a black box.
|
|
|
|
Copy the entire value string (everything up to but NOT including the
|
|
first linebreak char ) into the heap. initialize an arrayref
|
|
to access this string.
|
|
|
|
the following portion is also common to dereferenceValueMacro().
|
|
and partly common to ScanForMacroReferences()
|
|
|
|
Attempt to determine if the value in the heap is a string.
|
|
If so
|
|
{
|
|
parse along the string until macro reference is found
|
|
then lookup macroname in the valueMacroArray,
|
|
see how many bytes the macro contains and shift
|
|
the remainder of the referencing macrostring to make
|
|
room to insert the referenced macrostring.
|
|
Copy the referenced macrostring in the space provided.
|
|
Update the length of the referencing macrostring.
|
|
repeat until no other macro references are found.
|
|
}
|
|
else
|
|
do nothing special.
|
|
|
|
store ref to string in heap inside tokenArray.arValue
|
|
}
|
|
}
|
|
|
|
|
|
dereferenceValueMacro(index)
|
|
{
|
|
may want to factor out common stuff.
|
|
|
|
there is a macro reference in this statement since
|
|
it is flagged in the tokenMap.
|
|
|
|
|
|
if(valuetype for keywordID in the master keyword table != VALUE_COMMAND_INVOC
|
|
or VALUE_STRING)
|
|
{
|
|
expect macroref to be the first and only thing you
|
|
encounter.
|
|
|
|
convert macroref to macroID.
|
|
lookup macroID in valueMacroArray.
|
|
for(i = curValueMacroIndex ; i ; i--)
|
|
{
|
|
if(tokenMap[valueMacroArray[i - 1]].dwValue == macroID)
|
|
break; // p
|
|
}
|
|
If found, copy arrayref to value field which references Macro.
|
|
|
|
tokenMap[index].arValue = tokenMap[valueMacroArray[i - 1]].arValue
|
|
}
|
|
else // valueMacro occurs in a string.
|
|
{
|
|
Copy the entire value string (everything up to but NOT including the
|
|
first linebreak char ) into the heap.
|
|
parse along the string until macro reference is found
|
|
then lookup macroname in the valueMacroArray,
|
|
see how many bytes the macro contains and shift
|
|
the remainder of the referencing macrostring to make
|
|
room to insert the referenced macrostring.
|
|
Copy the referenced macrostring in the space provided.
|
|
Update the length of the referencing macrostring.
|
|
repeat until no other macro references are found.
|
|
Copy updated arrayref to value field in tokenMap.
|
|
}
|
|
}
|
|
|
|
|
|
defineSymbols(tokenMap) ???
|
|
{
|
|
Note: All Macro symbols have been processed
|
|
by the time this function is called.
|
|
|
|
Scans down tokenMap looking for
|
|
Feature:, Font: keywordIDs
|
|
and adding their symbol definitions to
|
|
the symbol tree. This portion may be common to
|
|
register macroname in ValueMacroSymbols tree
|
|
part of defineValueMacros() and defineBlockMacroSymbols()
|
|
|
|
|
|
|
|
then rescans (or in the same pass)
|
|
the tokenMap keeping track of
|
|
which Feature we are in, so when an Option
|
|
keyword is encountered, we know which Feature symbol
|
|
to associate the option symbol with. If an option
|
|
construct occurs outside of a Feature construct, we
|
|
will know and can flag this as an error.
|
|
|
|
}
|
|
|
|
|
|
at this point only symbols defined by Feature:, BlockMacros:, Font:
|
|
are stored in the symbol tree.
|
|
|
|
processSymbolRefs(tokenMap)
|
|
{
|
|
exactly which circustances may symbols appear outside of
|
|
a value? if they occur: keywordID should indicate
|
|
exactly what catagory of symbol and the symbolID.
|
|
in the high and low word.
|
|
|
|
replaces ptr to symbol values in source file
|
|
with SymbolID value or index to QualifiedName construct
|
|
or index to List construct which contains SymbolID value
|
|
or index to QualifiedName construct. tokenMap will
|
|
clearly identify which of the 4 cases applies.
|
|
|
|
At this point identify long or short version of command.
|
|
for short version, dwKeyWordID = SHORTCMD | <COMMANDID> ;
|
|
for long version : dwKeywordID = LONGCMD ;
|
|
and Cmd keyword dwKeywordID = CMD
|
|
dwValue = <COMMANDID> ;
|
|
Find and register dwKeywordID = SYMBOL in the appropriate
|
|
symbol Tree. Change dwKeywordID to (for example)
|
|
TTFONTNAME | FONTNAMEID.
|
|
|
|
At this point NO keywords should remain unrecognized.
|
|
}
|
|
|
|
|
|
main()
|
|
{
|
|
PTKMAP CreateTokenMap(
|
|
at what point do we distinguish between
|
|
shortcuts and non shortcut keywords? do this
|
|
soon, before BInterpretTokens() is called.
|
|
|
|
defineAndResolveMacros()
|
|
defineSymbols(tokenMap) ;
|
|
registers symbols for TTFontSubs?
|
|
processSymbolRefs(tokenMap) ;??? not needed at this time?
|
|
|
|
initStructures() with default or failsafe values ;
|
|
// this is done after first pass and we know
|
|
// how many DFEATURE_OPTION structures to allocate.
|
|
// we will initialize all dword values to ATTRIB_UNINITIALIZED.
|
|
// this is essential!
|
|
// the GlobalAttribute structure.
|
|
BInterpretTokens() ;
|
|
checkStructures() to ensure failsafe values have
|
|
been replaced - otherwise GPD file failed to
|
|
initialize some mandatory field.
|
|
|
|
verify that features that are referenced in switch
|
|
statements are indeed PICKONE. May force it to be
|
|
and warn or fail.
|
|
|
|
go through all allocated data structures ensuring
|
|
that they all contain at least the minimum required
|
|
fields. Supply defaults for any omitted but required
|
|
values. raise warnings. If a structure is fatally flawed,
|
|
you may have to fatally error out.
|
|
ConstructSeqCommandsArray() !
|
|
}
|
|
|
|
|
|
OpenIssues:
|
|
|
|
How to deal with TTFontSubs
|
|
|
|
*TTFontSubs: <On/Off>
|
|
{
|
|
symbolKeyname1: <integer>
|
|
symbolKeyname2: <integer>
|
|
symbolKeyname3: <integer>
|
|
...
|
|
}
|
|
|
|
the On/Off part is handled by
|
|
VsetbTTFontSubs(ptkmap->aarValue) ;
|
|
|
|
who handles the symbolKeywords? what if some are repeated?
|
|
ProcessSymbolKeyword(ptkmap + wEntry) ;
|
|
|
|
Both are called from within BInterpretTokens
|
|
|
|
|
|
// ---- tables of static data ---- //
|
|
|
|
// ---- The mainKeyword table ---- //
|
|
|
|
The mainKeyword Table is an array of
|
|
structures of the form:
|
|
|
|
typedef struct
|
|
{
|
|
PSTR pstrKeyword ; // keywordID is the index of this entry.
|
|
DWORD dwHashValue ; // optional - implement as time permits.
|
|
VALUE eAllowedValue ;
|
|
DWORD flAgs ;
|
|
TYPE eType; // may replace Type/Subtype with a function
|
|
DWORD dwSubType ; // if there is minimal code duplication.
|
|
DWORD dwOffset ; // into appropriate struct for attributes only.
|
|
// the size (num bytes to copy) of an attribute is easily determined
|
|
// from the AllowedValue field.
|
|
} KEYWORDTABLE_ENTRY;
|
|
|
|
|
|
global KEYWORDTABLE_ENTRY gMainKeywordTable[] =
|
|
{
|
|
static initializers
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
TY_CONSTRUCT, TY_ATTRIBUTE, TY_SPECIAL
|
|
} TYPE ;
|
|
|
|
typedef enum
|
|
{
|
|
SPCL_MEMCONFIGKB, SPCL_MEMCONFIGMB,
|
|
} SPECIAL ; // special subtypes
|
|
|
|
typedef enum
|
|
{
|
|
ATT_GLOBAL_ONLY, ATT_GLOBAL_FREEFLOAT,
|
|
ATT_LOCAL_FEATURE_ONLY, ATT_LOCAL_FEATURE_FF ,
|
|
ATT_LOCAL_OPTION_ONLY, ATT_LOCAL_OPTION_FF ,
|
|
ATT_LOCAL_COMMAND_ONLY, ATT_LOCAL_FONTCART_ONLY,
|
|
ATT_LOCAL_TTFONTSUBS_ONLY, ATT_LOCAL_OEM_ONLY,
|
|
ATT_LAST // Must be last in list.
|
|
} ATTRIBUTE ; // subtype
|
|
|
|
typedef enum
|
|
{
|
|
CONSTRUCT_UIGROUP ,
|
|
CONSTRUCT_FEATURE ,
|
|
CONSTRUCT_OPTION ,
|
|
CONSTRUCT_SWITCH,
|
|
CONSTRUCT_CASE ,
|
|
CONSTRUCT_DEFAULT ,
|
|
CONSTRUCT_COMMAND ,
|
|
CONSTRUCT_FONTCART ,
|
|
CONSTRUCT_TTFONTSUBS ,
|
|
CONSTRUCT_OEM ,
|
|
CONSTRUCT_LAST, // must end list of transition inducing constructs.
|
|
// constructs below do not cause state transitions
|
|
CONSTRUCT_BLOCKMACRO ,
|
|
CONSTRUCT_MACROS,
|
|
CONSTRUCT_OPENBRACE,
|
|
CONSTRUCT_CLOSEBRACE,
|
|
} CONSTRUCT ; // SubType if Type = CONSTRUCT
|
|
|
|
typedef enum
|
|
{
|
|
SPEC_CONSTR, SPEC_INS_CONSTR,
|
|
SPEC_NOT_INS_CONSTR, SPEC_INVALID_COMBO, SPEC_INVALID_INS_COMBO,
|
|
SPEC_MEM_CONFIG_KB, SPEC_MEM_CONFIG_MB, SPEC_FONT,
|
|
SPEC_, SPEC_, SPEC_,
|
|
} SPECIAL ;
|
|
|
|
|
|
typedef enum
|
|
{
|
|
NO_VALUE, VALUE_STRING, VALUE_COMMAND_INVOC,
|
|
VALUE_SYMBOL_DEF,
|
|
VALUE_SYMBOL_REF, VALUE_CONSTANT_catagory,
|
|
VALUE_INTEGER, VALUE_POINT, VALUE_RECT,
|
|
VALUE_BOOLEAN, VALUE_QUALIFIED_NAME,
|
|
VALUE_MAX
|
|
} VALUE ;
|
|
|
|
what does the parser expect after a keyword?
|
|
|
|
NO_VALUE : a linebreak OR an effective linebreak: ({) or comment
|
|
VALUE_STRING: Quoted String, hexstring, string MACROREF,
|
|
parameterless invocation.
|
|
VALUE_COMMAND_INVOC: like VALUE_STRING but allowed to contain
|
|
one or more parameter references.
|
|
VALUE_SYMBOL_DEF: Symbol definition - any value allowed
|
|
|
|
VALUE_SYMBOL_FIRST: base of user-defined symbol catagory
|
|
VALUE_SYMBOL_FEATURES = VALUE_SYMBOL_FIRST + SCL_FEATURES :
|
|
VALUE_SYMBOL_FONTCART = VALUE_SYMBOL_FIRST + SCL_FONTCART :
|
|
VALUE_SYMBOL_BLOCKMACRO = VALUE_SYMBOL_FIRST + SCL_BLOCKMACRO :
|
|
VALUE_SYMBOL_VALUEMACRO = VALUE_SYMBOL_FIRST + SCL_VALUEMACRO :
|
|
VALUE_SYMBOL_OPTIONS = VALUE_SYMBOL_FIRST + SCL_OPTIONS :
|
|
VALUE_SYMBOL_LAST = VALUE_SYMBOL_FIRST + SCL_NUMSYMCLASSES - 1 :
|
|
|
|
VALUE_CONSTANT_FIRST: base of enumeration catagory.
|
|
VALUE_CONSTANT_PRINTERTYPE = VALUE_CONSTANT_FIRST + CL_PRINTERTYPE ;
|
|
VALUE_CONSTANT_FEATURETYPE = VALUE_CONSTANT_FIRST + CL_FEATURETYPE ;
|
|
lots of class types listed here
|
|
..........
|
|
VALUE_CONSTANT_LAST = VALUE_CONSTANT_FIRST + CL_NUMCLASSES - 1 ;
|
|
VALUE_INTEGER: integer
|
|
VALUE_POINT: point
|
|
VALUE_RECT: rectangle
|
|
VALUE_BOOLEAN: boolean.
|
|
VALUE_QUALIFIED_NAME: Qualified name (one or more symbols separated by .)
|
|
VALUE_LIST: no attribute actually is assigned this descriptor,
|
|
// but used in the gValueToSize table.
|
|
VALUE_LARGEST: not a real descriptor, but this position in the
|
|
gValueToSize table holds the largest of the above values.
|
|
VALUE_MAX: number of elements in gValueToSize table.
|
|
|
|
-----
|
|
allowed values for KEYWORDTABLE_ENTRY.flAgs:
|
|
|
|
KWF_LIST: the value may be a LIST containing one or more
|
|
items of type AllowedValue. The storage format
|
|
must be of type LIST. Only certain values may qualify
|
|
for list format.
|
|
KWF_MACROREF_ALLOWED: since only a handful of keywords cannot accept
|
|
macro references, it may be a waste of a flag, but reserve this
|
|
to alert us that this special case must accounted for.
|
|
KWF_COMMAND: This attribute is stored in a dedicated structure
|
|
|
|
KWF_FONTCART: This attribute is stored in a dedicated structure
|
|
KWF_TTFONTSUBS: This attribute is stored in a dedicated structure
|
|
KWF_OEM: This attribute is stored in a dedicated structure
|
|
|
|
|
|
--------- special flag constructs ----
|
|
|
|
KWF_DEDICATED_FIELD = KWF_COMMAND | KWF_FONTCART |
|
|
KWF_TTFONTSUBS | KWF_OEM
|
|
|
|
: this indicates this attribute is stored
|
|
in a dedicated structure, not in the heap. As a result,
|
|
the dwOffset field is interpreted differently from attributes
|
|
without this flag set.
|
|
|
|
-----
|
|
|
|
Notes:
|
|
|
|
the KeywordTable is partitioned into sections:
|
|
non-attribute Keywords
|
|
GlobalAttributes
|
|
FeatureAttributes
|
|
OptionAttributes
|
|
CommandAttributes
|
|
etc.
|
|
A range of indicies (min-max)
|
|
may be provided or a special flag
|
|
may denote the last entry in each section.
|
|
The separation exists because the same keyword may
|
|
exist in two different sections.
|
|
-----
|
|
|
|
command array:
|
|
|
|
just a list of command names and #defines giving the unidrv
|
|
value. Use this table to assign each commandname a value.
|
|
CmdSelect is a special value -1!
|
|
|
|
|
|
typedef struct
|
|
{
|
|
ARRAYREF CommandName ;
|
|
DWORD UnidrvIndex ; // #define value assigned to command.
|
|
} CMD_TABLE ;
|
|
|
|
global CommandTable[NUM_UNIDRV_CMDS] ;
|
|
|
|
|
|
------
|
|
|
|
Table to convert allowed values to sizes:
|
|
|
|
DWORD gValueToSize[VALUE_MAX] ; // size of various values in bytes
|
|
|
|
VinitValueToSize()
|
|
{
|
|
// BUG_BUG! assume array is zero initialized
|
|
|
|
gValueToSize[VALUE_LARGEST] = 0 ;
|
|
gValueToSize[NO_VALUE] = 0 ;
|
|
gValueToSize[VALUE_BOOLEAN] = sizeof(BOOL) ; // etc
|
|
gValueToSize[VALUE_RECT] = sizeof(RECT) ; // etc
|
|
gValueToSize[VALUE_LIST] = sizeof(DWORD) ; // etc
|
|
// only the index of first listnode is stored.
|
|
|
|
|
|
for(i = 0 ; i < CL_NUMCLASSES ; i++)
|
|
gValueToSize[VALUE_CONSTANT_FIRST + i] = sizeof(DWORD) ;
|
|
|
|
for(i = 0 ; i < VALUE_MAX ; i++)
|
|
{
|
|
if (!gValueToSize[i])
|
|
assert! ; // ensure table is fully initialized .
|
|
if(gValueToSize[i] > gValueToSize[VALUE_LARGEST])
|
|
gValueToSize[VALUE_LARGEST] = gValueToSize[i] ;
|
|
}
|
|
}
|
|
|
|
|
|
-----
|
|
|
|
ensure all whitespaces are stripped before allowing token
|
|
to be registered, compared with etc.
|