source: OGRE/trunk/ogrenew/RenderSystems/GL/src/atifs/src/Compiler2Pass.cpp @ 657

Revision 657, 10.7 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.stevestreeting.com/ogre/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/gpl.html.
23-----------------------------------------------------------------------------
24*/
25#include <assert.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include "Compiler2Pass.h"
30
31Compiler2Pass::Compiler2Pass()
32{
33        // reserve some memory space in the containers being used
34        mTokenInstructions.reserve(100);
35        mConstants.reserve(80);
36        // default contexts allows all contexts
37        // subclass should change it to fit the language being compiled
38        mActiveContexts = 0xffffffff;
39
40}
41
42
43
44void Compiler2Pass::InitSymbolTypeLib()
45{
46        uint token_ID;
47        // find a default text for all Symbol Types in library
48
49        // scan through all the rules and initialize TypeLib with index to text and index to rules for non-terminal tokens
50        for(int i = 0; i < mRulePathLibCnt; i++) {
51                token_ID = mRootRulePath[i].mTokenID;
52                // make sure SymbolTypeLib holds valid token
53                assert(mSymbolTypeLib[token_ID].mID == token_ID);
54                switch(mRootRulePath[i].mOperation) {
55                        case otRULE:
56                                // if operation is a rule then update typelib
57                                mSymbolTypeLib[token_ID].mRuleID = i;
58
59                        case otAND:
60                        case otOR:
61                        case otOPTIONAL:
62                                // update text index in typelib
63                                if (mRootRulePath[i].mSymbol != NULL) mSymbolTypeLib[token_ID].mDefTextID = i;
64                                break;
65                }
66        }
67
68}
69
70
71bool Compiler2Pass::compile(const char* source)
72{
73        bool Passed = false;
74
75        mSource = source;
76        // start compiling if there is a rule base to work with
77        if(mRootRulePath != NULL) {
78                 Passed = doPass1();
79
80                if(Passed) {
81                        Passed = doPass2();
82                }
83        }
84        return Passed;
85}
86
87
88bool Compiler2Pass::doPass1()
89{
90        // scan through Source string and build a token list using TokenInstructions
91        // this is a simple brute force lexical scanner/analyzer that also parses the formed
92        // token for proper semantics and context in one pass
93
94        mCurrentLine = 1;
95        mCharPos = 0;
96        // reset position in Constants container
97        mConstants.clear();
98        mEndOfSource = strlen(mSource);
99
100        // start with a clean slate
101        mTokenInstructions.clear();
102        // tokenize and check semantics untill an error occurs or end of source is reached
103        // assume RootRulePath has pointer to rules so start at index + 1 for first rule path
104        // first rule token would be a rule definition so skip over it
105        bool passed = processRulePath(0);
106        // if a symbol in source still exists then the end of source was not reached and there was a problem some where
107        if (positionToNextSymbol()) passed = false;
108        return passed;
109
110}
111
112
113bool Compiler2Pass::processRulePath( uint rulepathIDX)
114{
115        // rule path determines what tokens and therefore what symbols are acceptable from the source
116        // it is assumed that the tokens with the longest similar symbols are arranged first so
117        // if a match is found it is accepted and no further searching is done
118
119        // record position of last token in container
120        // to be used as the rollback position if a valid token is not found
121        uint TokenContainerOldSize = mTokenInstructions.size();
122        int OldCharPos = mCharPos;
123        int OldLinePos = mCurrentLine;
124        uint OldConstantsSize = mConstants.size();
125
126        // keep track of what non-terminal token activated the rule
127        uint ActiveNTTRule = mRootRulePath[rulepathIDX].mTokenID;
128        // start rule path at next position for definition
129        rulepathIDX++;
130
131        // assume the rule will pass
132        bool Passed = true;
133        bool EndFound = false;
134
135        // keep following rulepath until the end is reached
136        while (EndFound == false) {
137                switch (mRootRulePath[rulepathIDX].mOperation) {
138
139                        case otAND:
140                                // only validate if the previous rule passed
141                                if(Passed) Passed = ValidateToken(rulepathIDX, ActiveNTTRule);
142                                break;
143
144                        case otOR:
145                                // only validate if the previous rule failed
146                                if ( Passed == false ) {
147                                        // clear previous tokens from entry and try again
148                                        mTokenInstructions.resize(TokenContainerOldSize);
149                                        Passed = ValidateToken(rulepathIDX, ActiveNTTRule);
150                                }
151                                else { // path passed up to this point therefore finished so pretend end marker found
152                                        EndFound = true;
153                                }
154                                break;
155
156                        case otOPTIONAL:
157                                // if previous passed then try this rule but it does not effect succes of rule since its optional
158                                if(Passed) ValidateToken(rulepathIDX, ActiveNTTRule);
159                                break;
160
161                        case otREPEAT:
162                                // repeat until no tokens of this type found
163                                // at least one must be found
164                                if(Passed) {
165                                        int TokensPassed = 0;
166                                        // keep calling until failure
167                                        while ( Passed = ValidateToken(rulepathIDX, ActiveNTTRule)) {
168                                                // increment count for previous passed token
169                                                TokensPassed++;
170                                        }
171                                        // defaults to Passed = fail
172                                        // if at least one token found then return passed = true
173                                        if (TokensPassed > 0) Passed = true;
174                                }
175                                break;
176
177                        case otEND:
178                                // end of rule found so time to return
179                                EndFound = true;
180                                if(Passed == false) {
181                                        // the rule did not validate so get rid of tokens decoded
182                                        // roll back the token container end position to what it was when rule started
183                                        // this will get rid of all tokens that had been pushed on the container while
184                                        // trying to validating this rule
185                                        mTokenInstructions.resize(TokenContainerOldSize);
186                                        mConstants.resize(OldConstantsSize);
187                                        mCharPos = OldCharPos;
188                                        mCurrentLine = OldLinePos;
189                                }
190                                break;
191
192                        default:
193                                // an exception should be raised since the code should never get here
194                                Passed = false;
195                                EndFound = true;
196                                break;
197
198                }
199
200
201                // move on to the next rule in the path
202                rulepathIDX++;
203        }
204
205        return Passed;
206
207}
208
209
210bool Compiler2Pass::ValidateToken(const uint rulepathIDX, const uint activeRuleID)
211{
212        int tokenlength = 0;
213        // assume the test is going to fail
214        bool Passed = false;
215        uint TokenID = mRootRulePath[rulepathIDX].mTokenID;
216        // only validate token if context is correct
217        if (mSymbolTypeLib[TokenID].mContextKey & mActiveContexts) {
218       
219                // if terminal token then compare text of symbol with what is in source
220                if ( mSymbolTypeLib[TokenID].mRuleID == 0){
221
222                        if (positionToNextSymbol()) {
223                                // if Token is supposed to be a number then check if its a numerical constant
224                                if (TokenID == mValueID) {
225                                        float constantvalue;
226                                        if(Passed = isFloatValue(constantvalue, tokenlength)) {
227                                                mConstants.push_back(constantvalue);
228                                        }
229                                       
230                                }
231                                // compare token symbol text with source text
232                                else Passed = isSymbol(mRootRulePath[rulepathIDX].mSymbol, tokenlength);
233                                       
234                                if(Passed) {
235                                        TokenInst newtoken;
236                                        // push token onto end of container
237                                        newtoken.mID = TokenID;
238                                        newtoken.mNTTRuleID = activeRuleID;
239                                        newtoken.mLine = mCurrentLine;
240                                        newtoken.mPos = mCharPos;
241
242                                        mTokenInstructions.push_back(newtoken);
243                                        // update source position
244                                        mCharPos += tokenlength;
245
246                                        // allow token instruction to change the ActiveContexts
247                                        // use token contexts pattern to clear ActiveContexts pattern bits
248                                        mActiveContexts &= ~mSymbolTypeLib[TokenID].mContextPatternClear;
249                                        // use token contexts pattern to set ActiveContexts pattern bits
250                                        mActiveContexts |= mSymbolTypeLib[TokenID].mContextPatternSet;
251                                }
252                        }
253
254                }
255                // else a non terminal token was found
256                else {
257
258                        // execute rule for non-terminal
259                        // get rule_ID for index into  rulepath to be called
260                        Passed = processRulePath(mSymbolTypeLib[TokenID].mRuleID);
261                }
262        }
263
264
265        return Passed;
266
267}
268
269
270char* Compiler2Pass::getTypeDefText(const uint sid)
271{
272        return mRootRulePath[mSymbolTypeLib[sid].mDefTextID].mSymbol;
273}
274
275
276bool Compiler2Pass::isFloatValue(float& fvalue, int& charsize)
277{
278        // check to see if it is a numeric float value
279        bool valuefound = false;
280
281        const char* startptr = mSource + mCharPos;
282        char* endptr = NULL;
283
284        fvalue = (float)strtod(startptr, &endptr);
285        // if a valid float was found then endptr will have the pointer to the first invalid character
286        if(endptr) {
287                if(endptr>startptr) {
288                        // a valid value was found so process it
289                        charsize = endptr - startptr;
290                        valuefound = true;
291                }
292        }
293
294        return valuefound;
295}
296
297
298bool Compiler2Pass::isSymbol(const char* symbol, int& symbolsize)
299{
300        // compare text at source+charpos with the symbol : limit testing to symbolsize
301        bool symbolfound = false;
302        symbolsize = strlen(symbol);
303        if(strncmp(mSource + mCharPos, symbol, symbolsize)==0) {
304                symbolfound = true;
305        }
306
307        return symbolfound;
308}
309
310
311bool Compiler2Pass::positionToNextSymbol()
312{
313        bool validsymbolfound = false;
314        bool endofsource = false;
315        while(!validsymbolfound && !endofsource) {
316                skipWhiteSpace();
317                skipEOL();
318                skipComments();
319                // have we reached the end of the string?
320                if (mCharPos == mEndOfSource) endofsource = true;
321                else {
322                        // if ASCII > space then assume valid character is found
323                        if (mSource[mCharPos] > ' ') validsymbolfound = true;
324                }
325        }// end of while
326
327        return validsymbolfound;
328}
329
330
331
332void Compiler2Pass::skipComments()
333{
334  // if current char and next are // then search for EOL
335        if(mCharPos < mEndOfSource) {
336                if( ((mSource[mCharPos] == '/') && (mSource[mCharPos + 1] == '/')) ||
337                        (mSource[mCharPos] == ';') ||
338                        (mSource[mCharPos] == '#') ) findEOL();
339        }
340}
341
342
343void Compiler2Pass::findEOL()
344{
345        // find eol charter and move to this position
346        const char* newpos = strchr(&mSource[mCharPos], '\n');
347        if(newpos) {
348                mCharPos += newpos - &mSource[mCharPos];
349        }
350        // couldn't find end of line so skip to the end
351        else mCharPos = mEndOfSource - 1;
352
353}
354
355
356void Compiler2Pass::skipEOL()
357{
358        if ((mSource[mCharPos] == '\n') || (mSource[mCharPos] == '\r')) {
359                mCurrentLine++;
360                mCharPos++;
361                if ((mSource[mCharPos] == '\n') || (mSource[mCharPos] == '\r')) {
362                        mCharPos++;
363                }
364        }
365}
366
367
368void Compiler2Pass::skipWhiteSpace()
369{
370        // FIX - this method kinda slow
371        while((mSource[mCharPos] == ' ') || (mSource[mCharPos] == '\t')) mCharPos++; // find first non white space character
372}
373
Note: See TracBrowser for help on using the repository browser.