📄 compiler2pass.cpp
字号:
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.stevestreeting.com/ogre/
Copyright © 2000-2004 The OGRE Team
Also see acknowledgements in Readme.html
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/gpl.html.
-----------------------------------------------------------------------------
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Compiler2Pass.h"
Compiler2Pass::Compiler2Pass()
{
// reserve some memory space in the containers being used
mTokenInstructions.reserve(100);
mConstants.reserve(80);
// default contexts allows all contexts
// subclass should change it to fit the language being compiled
mActiveContexts = 0xffffffff;
}
void Compiler2Pass::InitSymbolTypeLib()
{
uint token_ID;
// find a default text for all Symbol Types in library
// scan through all the rules and initialize TypeLib with index to text and index to rules for non-terminal tokens
for(int i = 0; i < mRulePathLibCnt; i++) {
token_ID = mRootRulePath[i].mTokenID;
// make sure SymbolTypeLib holds valid token
assert(mSymbolTypeLib[token_ID].mID == token_ID);
switch(mRootRulePath[i].mOperation) {
case otRULE:
// if operation is a rule then update typelib
mSymbolTypeLib[token_ID].mRuleID = i;
case otAND:
case otOR:
case otOPTIONAL:
// update text index in typelib
if (mRootRulePath[i].mSymbol != NULL) mSymbolTypeLib[token_ID].mDefTextID = i;
break;
}
}
}
bool Compiler2Pass::compile(const char* source)
{
bool Passed = false;
mSource = source;
// start compiling if there is a rule base to work with
if(mRootRulePath != NULL) {
Passed = doPass1();
if(Passed) {
Passed = doPass2();
}
}
return Passed;
}
bool Compiler2Pass::doPass1()
{
// scan through Source string and build a token list using TokenInstructions
// this is a simple brute force lexical scanner/analyzer that also parses the formed
// token for proper semantics and context in one pass
mCurrentLine = 1;
mCharPos = 0;
// reset position in Constants container
mConstants.clear();
mEndOfSource = strlen(mSource);
// start with a clean slate
mTokenInstructions.clear();
// tokenize and check semantics untill an error occurs or end of source is reached
// assume RootRulePath has pointer to rules so start at index + 1 for first rule path
// first rule token would be a rule definition so skip over it
bool passed = processRulePath(0);
// if a symbol in source still exists then the end of source was not reached and there was a problem some where
if (positionToNextSymbol()) passed = false;
return passed;
}
bool Compiler2Pass::processRulePath( uint rulepathIDX)
{
// rule path determines what tokens and therefore what symbols are acceptable from the source
// it is assumed that the tokens with the longest similar symbols are arranged first so
// if a match is found it is accepted and no further searching is done
// record position of last token in container
// to be used as the rollback position if a valid token is not found
uint TokenContainerOldSize = mTokenInstructions.size();
int OldCharPos = mCharPos;
int OldLinePos = mCurrentLine;
uint OldConstantsSize = mConstants.size();
// keep track of what non-terminal token activated the rule
uint ActiveNTTRule = mRootRulePath[rulepathIDX].mTokenID;
// start rule path at next position for definition
rulepathIDX++;
// assume the rule will pass
bool Passed = true;
bool EndFound = false;
// keep following rulepath until the end is reached
while (EndFound == false) {
switch (mRootRulePath[rulepathIDX].mOperation) {
case otAND:
// only validate if the previous rule passed
if(Passed) Passed = ValidateToken(rulepathIDX, ActiveNTTRule);
break;
case otOR:
// only validate if the previous rule failed
if ( Passed == false ) {
// clear previous tokens from entry and try again
mTokenInstructions.resize(TokenContainerOldSize);
Passed = ValidateToken(rulepathIDX, ActiveNTTRule);
}
else { // path passed up to this point therefore finished so pretend end marker found
EndFound = true;
}
break;
case otOPTIONAL:
// if previous passed then try this rule but it does not effect succes of rule since its optional
if(Passed) ValidateToken(rulepathIDX, ActiveNTTRule);
break;
case otREPEAT:
// repeat until no tokens of this type found
// at least one must be found
if(Passed) {
int TokensPassed = 0;
// keep calling until failure
while ( Passed = ValidateToken(rulepathIDX, ActiveNTTRule)) {
// increment count for previous passed token
TokensPassed++;
}
// defaults to Passed = fail
// if at least one token found then return passed = true
if (TokensPassed > 0) Passed = true;
}
break;
case otEND:
// end of rule found so time to return
EndFound = true;
if(Passed == false) {
// the rule did not validate so get rid of tokens decoded
// roll back the token container end position to what it was when rule started
// this will get rid of all tokens that had been pushed on the container while
// trying to validating this rule
mTokenInstructions.resize(TokenContainerOldSize);
mConstants.resize(OldConstantsSize);
mCharPos = OldCharPos;
mCurrentLine = OldLinePos;
}
break;
default:
// an exception should be raised since the code should never get here
Passed = false;
EndFound = true;
break;
}
// move on to the next rule in the path
rulepathIDX++;
}
return Passed;
}
bool Compiler2Pass::ValidateToken(const uint rulepathIDX, const uint activeRuleID)
{
int tokenlength = 0;
// assume the test is going to fail
bool Passed = false;
uint TokenID = mRootRulePath[rulepathIDX].mTokenID;
// only validate token if context is correct
if (mSymbolTypeLib[TokenID].mContextKey & mActiveContexts) {
// if terminal token then compare text of symbol with what is in source
if ( mSymbolTypeLib[TokenID].mRuleID == 0){
if (positionToNextSymbol()) {
// if Token is supposed to be a number then check if its a numerical constant
if (TokenID == mValueID) {
float constantvalue;
if(Passed = isFloatValue(constantvalue, tokenlength)) {
mConstants.push_back(constantvalue);
}
}
// compare token symbol text with source text
else Passed = isSymbol(mRootRulePath[rulepathIDX].mSymbol, tokenlength);
if(Passed) {
TokenInst newtoken;
// push token onto end of container
newtoken.mID = TokenID;
newtoken.mNTTRuleID = activeRuleID;
newtoken.mLine = mCurrentLine;
newtoken.mPos = mCharPos;
mTokenInstructions.push_back(newtoken);
// update source position
mCharPos += tokenlength;
// allow token instruction to change the ActiveContexts
// use token contexts pattern to clear ActiveContexts pattern bits
mActiveContexts &= ~mSymbolTypeLib[TokenID].mContextPatternClear;
// use token contexts pattern to set ActiveContexts pattern bits
mActiveContexts |= mSymbolTypeLib[TokenID].mContextPatternSet;
}
}
}
// else a non terminal token was found
else {
// execute rule for non-terminal
// get rule_ID for index into rulepath to be called
Passed = processRulePath(mSymbolTypeLib[TokenID].mRuleID);
}
}
return Passed;
}
char* Compiler2Pass::getTypeDefText(const uint sid)
{
return mRootRulePath[mSymbolTypeLib[sid].mDefTextID].mSymbol;
}
bool Compiler2Pass::isFloatValue(float& fvalue, int& charsize)
{
// check to see if it is a numeric float value
bool valuefound = false;
const char* startptr = mSource + mCharPos;
char* endptr = NULL;
fvalue = (float)strtod(startptr, &endptr);
// if a valid float was found then endptr will have the pointer to the first invalid character
if(endptr) {
if(endptr>startptr) {
// a valid value was found so process it
charsize = endptr - startptr;
valuefound = true;
}
}
return valuefound;
}
bool Compiler2Pass::isSymbol(const char* symbol, int& symbolsize)
{
// compare text at source+charpos with the symbol : limit testing to symbolsize
bool symbolfound = false;
symbolsize = strlen(symbol);
if(strncmp(mSource + mCharPos, symbol, symbolsize)==0) {
symbolfound = true;
}
return symbolfound;
}
bool Compiler2Pass::positionToNextSymbol()
{
bool validsymbolfound = false;
bool endofsource = false;
while(!validsymbolfound && !endofsource) {
skipWhiteSpace();
skipEOL();
skipComments();
// have we reached the end of the string?
if (mCharPos == mEndOfSource) endofsource = true;
else {
// if ASCII > space then assume valid character is found
if (mSource[mCharPos] > ' ') validsymbolfound = true;
}
}// end of while
return validsymbolfound;
}
void Compiler2Pass::skipComments()
{
// if current char and next are // then search for EOL
if(mCharPos < mEndOfSource) {
if( ((mSource[mCharPos] == '/') && (mSource[mCharPos + 1] == '/')) ||
(mSource[mCharPos] == ';') ||
(mSource[mCharPos] == '#') ) findEOL();
}
}
void Compiler2Pass::findEOL()
{
// find eol charter and move to this position
const char* newpos = strchr(&mSource[mCharPos], '\n');
if(newpos) {
mCharPos += newpos - &mSource[mCharPos];
}
// couldn't find end of line so skip to the end
else mCharPos = mEndOfSource - 1;
}
void Compiler2Pass::skipEOL()
{
if ((mSource[mCharPos] == '\n') || (mSource[mCharPos] == '\r')) {
mCurrentLine++;
mCharPos++;
if ((mSource[mCharPos] == '\n') || (mSource[mCharPos] == '\r')) {
mCharPos++;
}
}
}
void Compiler2Pass::skipWhiteSpace()
{
// FIX - this method kinda slow
while((mSource[mCharPos] == ' ') || (mSource[mCharPos] == '\t')) mCharPos++; // find first non white space character
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -