ot_parse.cpp
来自「在手机操作系统symbina上使用的一个脚本扩展语言的代码实现,可以参考用于自己」· C++ 代码 · 共 1,028 行 · 第 1/2 页
CPP
1,028 行
// If this is a definition of a PROC, them there is allowed to be an existing
// declaration _PROVIDED_ that it has the same signature
if (aFlag==EDefinition)
{
COplSymbol* declaration=iSymbols->Find(*name,TOplToken::EProcId);
if (declaration) // There's an existing symbol
{
if (declaration->Class()!=COplSymbol::EProcDecl) // But it's not a declaration
User::Leave(EErrDuplicateName);
// Signatures must match
if (!(signature==STATIC_CAST(COplCallSymbol *,declaration)->Signature()))
User::Leave(EErrIncompatibleDeclaration);
iSymbols->Delete(declaration);
}
}
// Now get the symbol and set the signature
COplCallSymbol *symbol=STATIC_CAST(COplCallSymbol *,COplDeclarationSymbol::NewLC(aClass,TOplToken::EProcId,signature.ReturnType(),*name));
symbol->Signature()=signature;
AddSymbolL(*symbol);
CleanupStack::Pop(); // Safe now
CleanupStack::PopAndDestroy(); // function name
return *symbol;
}
void COplModuleParser::ConstantDeclarationL()
//
// CONST simple-id = [-] constant EOS
//
// Already seen the leading CONST
//
{
MustBeL(TOplToken::ESimple); // simpleId
COplConstantSymbol &symbol=*(COplConstantSymbol *)NewSymbolL(COplSymbol::EConstant);
MustBeL(TOplToken::EEqual); // '='
TBool negate=EFalse; // [-]
if (NextIsL(TOplToken::EMinus))
negate=ETrue;
MustBeL(TOplToken::EConstant); // Constant
// Deliberately don't try and assign the TOplConstant directly.
// as the assignments contain any casts between what was declared for the vrable type
// and what was actually given forthe initializer
TOplConstant& constant=Lexer().Constant();
if (negate)
constant.NegateL();
switch (symbol.Type())
{
case TOplToken::EWord:
symbol.Value()=constant.AsWordL();
break;
case TOplToken::ELong:
symbol.Value()=constant.AsLongL();
break;
case TOplToken::EReal:
symbol.Value()=constant.AsRealL();
break;
case TOplToken::EString:
symbol.Value()=*constant.AsStringL().AllocL();
default: // To keep GCC happy - but we know better
break;
}
EosL();
}
void COplModuleParser::OpxDeclareBlockL()
//
// declare-block := DECLARE OPX <name>,<version> EOS
// declare-function-list
// END DECLARE
//
// functionList:= [procId [( [arg-decl[,arg-decl]*] )] : function-number Eos]*
// Fix OPL Ha-26 allow no arguments in declare
// Fix: remove alias and add OPX function number so linkage is by
// ordinal.
//
// arg-decl := [BYREF] simple-id
//
// We've already seen the leading DECLARE.
//
{
TInt opxNumber=iBackEnd->OpxCount();
if (opxNumber==(TInt)KOplMaxOpxCount)
User::Leave(EErrTooManyOPXs);
// DECLARE OPX <name>, <uid>, <version> EOS
{
COplParseOpx* opx=COplParseOpx::NewLC();
MustBeL(TOplToken::EOpx);
MustBeL(TOplToken::ESimple); // <name>
if (Lexer().Type()!=TOplToken::EReal)
SyntaxErrorL();
opx->SetNameL(Lexer().Name());
CommaL();
MustBeL(TOplToken::EConstant); // <uid>
opx->SetUid(TUid::Uid(Lexer().Constant().AsLongL()));
CommaL(); // comma
MustBeL(TOplToken::EConstant); // <version>
opx->SetVersion(Lexer().Constant().AsWordL());
EosL();
iBackEnd->OpxL(opx); // This takes ownership of the object IF it succeeds
CleanupStack::Pop(); // OPX is safe or destroyed
}
// functionList:= [procId ( [arg-decl [,arg-decl]*] ) : function-number Eos]*
while (SkipBlankLinesL()==TOplToken::EProcId)
{
Lexer().UnLex();
COplSymbol& symbol=ProcedureDeclarationL(COplSymbol::EOpxFunction,EDeclaration); // procId ( [arg-decl [,arg-decl]*] )
MustBeL(TOplToken::EColon); // :
MustBeL(TOplToken::EConstant); // function-number
symbol.SetAddress(TOpxAddress(opxNumber,Lexer().Constant().AsWordL()));
// EOS
EosL();
}
Lexer().UnLex();
// END DECLARE EOS
MustBeL(TOplToken::EEnd);
MustBeL(TOplToken::EDeclare);
EosL();
}
void COplModuleParser::ProcL()
//
// PROC proc-id [(decl-list)] EOS
// auto-decl-lists
// statement-list
// ENDP
//
// auto-decl-lists := [GLOBAL | LOCAL decl-list EOS]*
//
// NOTE _ We've already had the PROC
//
{
// If we're trying to find a run-time error
TInt errorOffset=KOplNoErrorLocation;
if (iLocatingError)
{
if (iLineNumber!=Lexer().LineNumber()) // This is not the one we're looking for
{
// So just skip through to the ENDP
TOplToken next;
FOREVER
{
TRAPD(ret, next=SkipToEndL());
if (ret==KErrNone)
break;
// Got an error skipping through the tokens. Assuming that
// the runtime is asking us to find an error in a legitimate function
// this can only happen because the lexer doesn't understand the character after
// %. So we gobble the next character and press on.
TRAP(ret,Lexer().NextChar());
}
if (next==TOplToken::EEof)
User::Leave(EErrUnexpectedEof);
return;
}
// This is the one that we're looking for.
errorOffset=iQcodeOffset;
}
// ... proc-id [(decl-list)] EOS
// Now we parse the name and argument list once to get the declaration
// i.e. record and check the signature
Lexer().Mark();
ProcedureDeclarationL(COplSymbol::EProcDecl,EDefinition);
// We do it again, primarily to get the symbols for the arguments
// into the symbol table and within the right scope.
// It's a bit of a kludge but it's the safest fix
Lexer().UnGetToMark();
MustBeL(TOplToken::EProcId); // proc-id
iBackEnd->StartProcL(Lexer().Name(),Lexer().LineNumber(),errorOffset); // Checks for duplicate definitions
// Various house-keeping things.
iProcHeader=COplProcHeader::NewLC(Lexer().Type());
CBufSeg *codeBuf=CBufSeg::NewL(KOplPcodeGran);
CleanupStack::PushL(codeBuf);
iCode.Insert(*codeBuf,0); // Open it as an insert stream so we can come back an insert stuff at a later time
Mem::FillZ(&iBranches,sizeof(TBranches));
// Variables declared within the PROC..ENDP are scoped within PROC ENDP.
iSymbols->StartScope();
// [ ( arg-decl-list) ] EOS
if (NextIsL(TOplToken::EOpenBracket))
{
DeclarationListL(COplSymbol::EArgument);
MustBeL(TOplToken::ECloseBracket);
}
EosL();
// auto-decl-lists
FOREVER
{
TOplToken next=SkipBlankLinesL();
COplSymbol::TClass declClass=COplSymbol::EConstant; // Used to indicate that it is not a declation
switch (next)
{
case TOplToken::ELocal:
declClass=COplSymbol::ELocal;
break;
case TOplToken::EGlobal:
declClass=COplSymbol::EGlobal;
break;
case TOplToken::EExternal:
declClass=COplSymbol::EExternalDecl;
default:
break;
}
if (declClass==COplSymbol::EConstant)
{
Lexer().UnLex();
break;
}
DeclarationListL(declClass);
EosL();
}
// statement-list
// ENDP
if (StatementListL()!=TOplToken::EEndP)
SyntaxErrorL();
// Procedures always return a value
if (!iLastWasReturn)
PCodeTypedCommandL(TOplKeyword::EReturnNull,iProcHeader->Type());
// Pass it all through to the back end - which take ownership of the objects
iBackEnd->ProcL(iProcHeader,codeBuf);
CleanupStack::Pop(2); // Code buf & Procedure Header
iProcHeader=NULL;
iSymbols->EndScope();
}
TInt COplModuleParser::DeclarationIndexL()
//
// Deals with an index for an array or string
//
{
if (!NextIsL(TOplToken::EConstant))
User::Leave(EErrBadArraySize);
TInt size=0;
TRAPD(ret,size=Lexer().Constant().AsWordL());
if (ret!=KErrNone || size<=0)
User::Leave(EErrBadArraySize);
return size;
}
void COplModuleParser::DeclarationListL(COplSymbol::TClass aClass)
//
// decl-list := decl [,decl]*
//
//
{
TBool isAutomatic=(aClass==COplSymbol::ELocal || aClass==COplSymbol::EGlobal);
do
{
TOplToken id=NextL();
if (id!=TOplToken::ESimple && id!=TOplToken::EArray)
User::Leave(EErrBadDeclaration);
COplSymbol* pSymbol=NewSymbolL(aClass);
if (id==TOplToken::ESimple)
{
// Strings automatics must have a length (so look like arrays)
if (pSymbol->Type()==TOplToken::EString && isAutomatic)
User::Leave(EErrBadDeclaration);
}
else // It's an array - or at least a String declaration
{
if (!isAutomatic) // External or Argument
{
// Arguments can't be arrays
if (aClass==COplSymbol::EArgument)
User::Leave(EErrBadDeclaration);
}
else // 'Proper' automatic declaration - need to get array size
{
COplAutomaticSymbol *pAuto=STATIC_CAST(COplAutomaticSymbol *,pSymbol);
TInt arraySize=DeclarationIndexL();
if (pAuto->Type()==TOplToken::EString)
{
TInt stringLength=0;
if (NextIsL(TOplToken::EComma)) // It's a string array
stringLength=DeclarationIndexL();
else // Actually just a simpl string declaration, rather than an array
{
stringLength=arraySize;
arraySize=0;
pAuto->SetToken(TOplToken(TOplToken::ESimple));
}
if (stringLength>KOplMaxStringLength)
User::Leave(EErrBadStringLength);
pAuto->SetStringLen(stringLength);
}
pAuto->SetArraySize(arraySize);
}
if (!NextIsL(TOplToken::ECloseBracket))
User::Leave(EErrBadDeclaration);
}
} while (NextIsL(TOplToken::EComma));
}
TOplToken COplModuleParser::StatementListL()
//
//
//
{
TOplToken next;
iLastWasReturn=EFalse; // For empty lists
FOREVER
{
FOREVER
{
next=NextL();
if (next!=TOplToken::ELabel)
break;
DefineLabelL(Lexer().Name());
}
if (next.Class()==TOplToken::EReserved) // A structural word
break;
iLastWasReturn=EFalse; // Assume next statement is not a return.
PCodeL(TPcode::EStatement); // IN debug mode this will put out the statement code for the debugger
switch (next.Class())
{
case TOplToken::EOperator:
SyntaxErrorL();
case TOplToken::EPunctuation:
if (next==TOplToken::EEof)
User::Leave(EErrUnexpectedEof);
if (!IsEos(next))
SyntaxErrorL();
continue;
case TOplToken::EIdentifier:
IdentifierStatementL(next);
break;
case TOplToken::EKeyword:
KeywordStatementL(); // Will set iLastWasReturn appropriately
break;
case TOplToken::ECall:
CallStatementL(next);
break;
case TOplToken::EStructure:
StructureL(next);
iLastWasReturn=EFalse; // Otherwise, can get fooled by while 0 : if 0 : return endif endwh endp
case TOplToken::EReserved: // Here solely to stop the compiler winging about stuff
break;
}
EosL();
}
return next;
}
TOplToken COplModuleParser::SkipBlankLinesL()
//
// Skips to the next token that isn't Eos
//
{
TOplToken next;
do
{
next=Lexer().LexL();
} while (IsEos(next));
return next;
}
TBool COplModuleParser::IsEos(TOplToken aToken)
//
// Deals with the fact that both TOPlToken::EEos && TOplToken::EColon can be EEos
// within the Module Parser
//
{
return (aToken==TOplToken::EEos || aToken==TOplToken::EColon);
}
void COplModuleParser::EosL()
//
// Next thing must be the end of a statement
//
{
TOplToken next=NextL();
if (!IsEos(next))
{
if (next==TOplToken::EOpenBracket || next==TOplToken::ECloseBracket)
User::Leave(EErrMismatchedBracket);
SyntaxErrorL();
}
}
TBool COplModuleParser::TestEosL()
//
// Peeks (lex & unlex) and checks if it is Eos
//
{
TOplToken next=NextL();
Lexer().UnLex();
return IsEos(next);
}
TBool COplModuleParser::NextIsOffL()
//
// Checks to see if the next thing is off
//
{
TBool ret=EFalse;
if (NextIsL(TOplToken::EKeywordToken))
{
if (Lexer().Keyword().Code()!=TOplKeyword::EOff)
Lexer().UnLex();
else
ret=ETrue;
}
return ret;
}
TBool COplModuleParser::NextIsOffOrOnL(TInt32& aQualifier)
//
// If OFF returns TRUE
// ELSE
// qualifier is incremented
// IF ON returns TRUE
// ELSE returns False
//
//
{
TBool ret=ETrue;
if (!NextIsOffL())
{
aQualifier++;
ret=NextIsL(TOplToken::EOn);
}
return ret;
}
TOplToken COplModuleParser::SkipToEndL()
//
// Skips to EndP or Eof
//
{
TOplToken next;
do
{
next=NextL();
} while (next!=TOplToken::EEndP && next!=TOplToken::EEof);
return next;
}
/////////////////////////////////////////////////////////////////////
//
// COplEvalParser
//
/////////////////////////////////////////////////////////////////////
COplEvalParser *COplEvalParser::NewL()
//
// Creates a new eval parser
//
{
COplEvalParser *pP=new(ELeave) COplEvalParser;
CleanupStack::PushL(pP);
pP->ConstructL();
CleanupStack::Pop();
return pP;
}
void COplEvalParser::ParseExpressionL(COplLineLexer& aLexer, TTranslateError& anError, COpl16EvalBackEnd& aBackEnd)
//
// Parses an expression
//
{
// Get a Pcode Buffer
CBufSeg *codeBuf=CBufSeg::NewL(KOplPcodeGran);
CleanupStack::PushL(codeBuf);
iCode.Insert(*codeBuf,0);
// Set up the lexer
Start(aLexer,anError);
// Parse the expression
ExpressionL(TOplToken::EReal); // Do a real expression
PCodeCommandL(TOplKeyword::EReturnFromEval);
// And convert it into Qcode with the appropriate references
aBackEnd.ProcessExpressionL(*codeBuf);
CleanupStack::PopAndDestroy(); // PCode buffer and do a reset
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?