Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/GL/src/atifs/src/Compiler2Pass.cpp @ 5

Last change on this file since 5 was 5, checked in by anonymous, 17 years ago

=hoffentlich gehts jetzt

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