ot_call.cpp
来自「在手机操作系统symbina上使用的一个脚本扩展语言的代码实现,可以参考用于自己」· C++ 代码 · 共 481 行
CPP
481 行
// OT_CALL.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd. All rights reserved.
//
#include "ot_std.h"
///////////////////////////////////////////////////////////////////
//
// TSignature - Holds the argument & returns type signature of a
// function or procedure
//
///////////////////////////////////////////////////////////////////
void TOplSignature::Initialize(TOplToken::TType aReturnType)
{
iReturnType=TUint8(aReturnType);
iNeedsCount=ETrue;
iPermittedArgumentCounts=0;
iArgumentCount=0;
Mem::Fill(iArgTypes,KOplMaxArgCount,TChar((TUint)EArgBadType));
}
void TOplSignature::SetArgumentCount(TUint anArgumentCount)
//
// Sets the argument count and allows it.
// Used in the case of implicit argument lists where there
// is no doubt about the number of permitted arguments
//
{
iArgumentCount=TUint8(anArgumentCount);
AllowArgumentCount(anArgumentCount);
}
void TOplSignature::AllowArgumentCount(TUint anArgCount)
{
// A call needs an argument count unless the function
// only permits one argument count.
iNeedsCount=TUint8(!!iPermittedArgumentCounts);
AllowArgumentCountByPass(anArgCount);
}
void TOplSignature::AllowArgumentCountByPass(TUint anArgCount)
//
// This by passes the check for whether or not the
// function has mutiple allowed arguments (and so needs the argument count)
// adding to the qcode. This is used by one of the mad overloaded functions
// (this language is such a mess)
//
{
iPermittedArgumentCounts|=(1<<anArgCount);
}
void TOplSignature::AddArgument(TUint anArgument,TArgType aType)
//
// Adds an argument to the signature
//
{
__ASSERT_ALWAYS(anArgument<(TUint)KOplMaxArgCount,Panic(EOpltTooManyArguments));
iArgTypes[anArgument]=(TUint8)aType;
}
TInt TOplSignature::operator==(const TOplSignature& aSignature) const
//
// Memberwise comparison
//
{
return (iReturnType==aSignature.iReturnType &&
iNeedsCount==aSignature.iNeedsCount &&
iArgumentCount==aSignature.iArgumentCount &&
iPermittedArgumentCounts==aSignature.iPermittedArgumentCounts &&
Mem::Compare(iArgTypes,KOplMaxArgCount,aSignature.iArgTypes,KOplMaxArgCount)==0);
}
TOplSignature::TArgType TOplSignature::operator[](TInt anArg) const
//
// Returns the argument type of the passed argument number
//
{
__ASSERT_ALWAYS(anArg<KOplMaxArgCount && anArg>=0,Panic(EOpltIllegalArgIndex));
return TArgType(iArgTypes[anArg]);
}
TOplToken::TType COplParserBase::ArgumentByRefL()
//
// Parses an identifier that is going to be passed by reference.
// Puts out the left side and then the call to Addr
// ArgumentByRef := # WordExpression
// | LeftSideReference
//
{
TOplToken next=NextL();
TOplToken::TType type=TOplToken::EBadType; // Returned to signal it's actually a #Reference
if (next==TOplToken::EHash)
NativeExpressionL();
else if (next.Class()!=TOplToken::EIdentifier || next==TOplToken::EConstant || next==TOplToken::ELabel)
User::Leave(EErrFnArgument);
else
{
PCodeL(TPcode::EArgList);
type=Lexer().Type();
LeftSideReferenceL(next,ESupplyIndices);
PCodeArgumentL(TPcode::EFunctionArg,TOplSignature::EArgAnyRef);
TOplFunction::TNumber addr=TOplFunction::EAddr;
if (type==TOplToken::EString)
addr=TOplFunction::ESAddr;
PCodeL(TPcode::EFixedFunctionCall);
iCode<<TUint8(1)<<NativeType()<<addr;
}
return type;
}
void COplParserBase::ArgumentByRefL(TOplToken::TType argType)
//
// Parse a function argument that is an identifier passed by reference.
// Checks that the type of the identifier is as required
//
{
TOplToken::TType type=ArgumentByRefL();
// EBadType indicates that it was actually a #expression reference,
// Otherwise the type must be as expected
if (type!=TOplToken::EBadType && type!=argType)
User::Leave(EErrFnArgument);
}
TBool COplParserBase::NextIsArgumentSeparatorL()
{
return (NextIsCommaL() || NextIsL(TOplToken::ESemiColon));
}
void COplParserBase::PCodeArgumentL(TPcode::TCode anArgCode, TOplSignature::TArgType anArgType)
//
//
//
{
PCodeL(anArgCode);
iCode<<anArgType;
}
TUint COplParserBase::ExplicitArgumentListL(TPcode::TCode anArgCode,TOplSignature& aSignature, TOplFunction* aFunction)
//
// Parse an argument list to something callable.
//
{
PCodeL(TPcode::EArgList);
TUint argCount=0;
if (aSignature.IsStatistical()) // Stats functions like Min/Max
{ // Which can either take an ArrayReference & count, or a number of arguments
MustBeL(TOplToken::EOpenBracket);
TBool isArray=EFalse;
Lexer().Mark(); // We're going to have a quick sniff and see which case we have
if (NextIsL(TOplToken::EArray) && Lexer().Type()==TOplToken::EReal && NextIsL(TOplToken::ECloseBracket))
isArray=ETrue;
Lexer().UnGetToMark(); // OK put it all back.
if (isArray) // RealArrayId ) , WordExpression
{
LeftSideReferenceL(NextL(),ESupplyIndices);
PCodeArgumentL(anArgCode,TOplSignature::EArgWordRef); // \\\???
if (!NextIsArgumentSeparatorL())
User::Leave(EErrFnArgument);
WordExpressionL();
PCodeArgumentL(anArgCode,TOplSignature::EArgWord);
}
else do // RealExpressionL[,RealExpression]*
{
ExpressionL(TOplToken::EReal);
PCodeArgumentL(anArgCode,TOplSignature::EArgReal);
argCount++;
} while (NextIsArgumentSeparatorL());
MustBeL(TOplToken::ECloseBracket);
}
else // It's a regular Min/Max kind of argument list.
{
if (NextIsL(TOplToken::EOpenBracket)) // Appears to have a regular argument lisr
{
if (aFunction!=NULL)
{
if (aFunction->Number()==TOplFunction::EMPopup)
aSignature.AllowArgumentCount(5);
}
do // each argument
{
TOplSignature::TArgType argType=aSignature[argCount];
switch (argType)
{
case TOplSignature::EArgWord:
case TOplSignature::EArgLong:
case TOplSignature::EArgReal:
case TOplSignature::EArgString:
case TOplSignature::EArgUword:
ExpressionL(TOplToken::TType(argType-TOplSignature::EArgWord+TOplToken::EWord));
break;
case TOplSignature::EArgNative:
NativeExpressionL();
break;
case TOplSignature::EArgUNative:
ExpressionL(UnsignedNativeType());
break;
case TOplSignature::EArgWordRef:
case TOplSignature::EArgLongRef:
case TOplSignature::EArgRealRef:
case TOplSignature::EArgStringRef:
ArgumentByRefL(TOplToken::TType(argType-TOplSignature::EArgWordRef+TOplToken::EWord));
break;
case TOplSignature::EArgAnyRef:
ArgumentByRefL();
break;
case TOplSignature::EArgOverLoad: // Special case where the argument type changes the function number
__ASSERT_ALWAYS(aFunction!=NULL,Panic(EOpltUnknownFunctionOverload));
switch (aFunction->Number())
{
case TOplFunction::EAddr:
{
TOplToken next=NextL();
if (next.Class()!=TOplToken::EIdentifier)
SyntaxErrorL();
argType=TOplSignature::TArgType(TOplSignature::EArgWordRef+Lexer().Type()-TOplToken::EWord);
if (argType==TOplSignature::EArgStringRef)
aFunction->SetNumber(TOplFunction::ESAddr);
LeftSideReferenceL(next,ESupplyIndices);
}
break;
case TOplFunction::EIoOpen:
{
argType=TOplSignature::TArgType(ExpressionL());
if (argType!=TOplSignature::EArgString)
{
aFunction->SetNumber(TOplFunction::EIoOpenX);
PCodeCastL(TOplToken::TType(argType),NativeType());
argType=TOplSignature::EArgNative;
}
}
break;
case TOplFunction::EgCreate:
WordExpressionL();
argType=TOplSignature::EArgWord;
aFunction->SetNumber(TOplFunction::EgCreateGrey);
aSignature.AllowArgumentCountByPass(argCount+1);
break;
case TOplFunction::EMenu:
ArgumentByRefL(TOplToken::EWord);
argType=TOplSignature::EArgWordRef;
aFunction->SetNumber(TOplFunction::EMenuX);
aSignature.AllowArgumentCountByPass(argCount+1);
break;
case TOplFunction::EMPopup: // mPopup(x%,y%,posType%,n1$,k1%[,n$,k%]+)
do
{
StringExpressionL();
PCodeArgumentL(anArgCode,TOplSignature::EArgString);
if (!NextIsArgumentSeparatorL())
User::Leave(EErrFnArgument);
WordExpressionL();
PCodeArgumentL(anArgCode,TOplSignature::EArgWord);
argCount+=2; // count pairs
} while (NextIsArgumentSeparatorL());
argCount--; // 1 added later
aSignature.AllowArgumentCount(argCount+1);
break;
case TOplFunction::EgCreateBit: // gCreateBit (w%,h%) for OPL1993, gCreateBit(w%,h%[,mode%]) for opler1
WordExpressionL();
if (!TargetIsOpl1993()) // Variable arguments
aSignature.AllowArgumentCount(3); // Can now have 2 or 3 arguments - hence count
break;
default:
Panic(EOpltUnknownFunctionOverload);
}
break;
default:
User::Leave(EErrFnArgument);
}
PCodeArgumentL(anArgCode,argType);
argCount++;
} while (NextIsArgumentSeparatorL());
MustBeL(TOplToken::ECloseBracket);
}
if (!aSignature.IsPermittedArgumentCount(argCount))
User::Leave(EErrFnArgument);
}
return argCount;
}
TUint COplParserBase::ImplicitArgumentListL(TPcode::TCode anArgCode,TOplSignature* aSignature)
//
// Parses an, as yet, undefined signature. A defining argument list
// I.e. the argument list for an implicitly declared procedure
//
{
PCodeL(TPcode::EArgList);
TInt argCount=0;
if (NextIsL(TOplToken::EOpenBracket))
{
do
{
TOplSignature::TArgType argType=TOplSignature::TArgType(ExpressionL());
if (aSignature!=NULL)
aSignature->AddArgument(argCount,argType);
PCodeArgumentL(anArgCode,argType);
argCount++;
} while (NextIsArgumentSeparatorL());
MustBeL(TOplToken::ECloseBracket);
}
if (aSignature!=NULL)
aSignature->SetArgumentCount(argCount);
return argCount;
}
TOplToken::TType COplParserBase::CallL(TOplToken aToken)
//
// Don't put stuff on the stack unnecessarily as this can be horribly
// recursive.
// Something callable - procedure/function/OPX
// In all cases we have just lexed the first token.
// Call := CallId [ argument-list]
{
TOplToken::TType returnType=Lexer().Type();
switch (aToken)
{
case TOplToken::EOpxFunction:
{
COplCallSymbol *pSym=Lexer().OpxSymbol();
ExplicitArgumentListL(TPcode::EOpxArg,pSym->Signature(),NULL);
PCodeL(TPcode::EOpxCall);
iCode<<(COplSymbol *)pSym;
break;
}
case TOplToken::EProcId: // ProcId ProcArgumentList
{
ProcCallPreambleL(Lexer().Name(),returnType);
COplSymbol *pSym=iSymbols->Find(Lexer().Name(),aToken);
COplReferenceSymbol *pRef=NULL;
if (pSym==NULL) // This is the first reference so it actually counts as the declaration
{
if (iExplicitDefines) // BUT banned from implicit definitions
User::Leave(EErrUndefinedProcedure);
pSym=NewSymbolL(COplSymbol::EProcDecl);
// Since this is the first time, we use this to determine the signature
TOplSignature& signature=((COplCallSymbol*)pSym)->Signature();
signature.Initialize(pSym->Type());
ImplicitArgumentListL(TPcode::EProcArg,&signature); // Get the signature for the symbol
// Finally add the reference
pRef=ReferenceL(*pSym); // And stick in the reference
}
else
{
pRef=(pSym->Class()==COplSymbol::EProcRef ? (COplReferenceSymbol *)pSym : ReferenceL(*pSym));
ExplicitArgumentListL(TPcode::EProcArg,((COplCallSymbol&)pRef->Declaration()).Signature(),NULL);
}
ProcCallPostambleL(pRef);
}
break;
case TOplToken::EProcByName: // ProcByName StringExression ) : ProcedureArgumentList
{
StringExpressionL(); // The procedure name
PCodeL(TPcode::EProcCallName); // Marks the name on the stack for the Munger's benefit
MustBeL(TOplToken::ECloseBracket);
MustBeL(TOplToken::EColon);
PCodeProcByNameL(returnType,ImplicitArgumentListL(TPcode::EProcArg));
}
break;
case TOplToken::EFunction: // [(FunctionArgumentList|StatsArgumentList)]
{
// We allocate a copy of the function since it's only held temporarily
// within the lexer & this is all horribly reursive
TOplFunction *pF=(TOplFunction *)User::AllocLC(sizeof(TOplFunction));
new(pF) TOplFunction(Lexer().Function());
TUint argCount=ExplicitArgumentListL(TPcode::EFunctionArg,pF->Signature(),pF);
PCodeL(pF->Signature().NeedsArgumentCount() ? TPcode::ECountedFunctionCall : TPcode::EFixedFunctionCall);
if (returnType==TOplToken::ENativeReturn)
returnType=NativeType();
iCode<<TUint8(argCount)<<returnType<<pF->Number();
CleanupStack::PopAndDestroy(); // Kill off function details
break;
}
default:
Panic(EOpltUnknownCallType);
}
return returnType;
}
void COplParserBase::ProcCallPreambleL(const TDesC& /*aName*/,TOplToken::TType /* aType*/)
//
// Does nothing in the base
//
{
}
void COplParserBase::PCodeProcByNameL(TOplToken::TType aType,TUint anArgumentCount)
//
// Puts out the Pcode for calling a proc by name
//
{
PCodeL(TPcode::EProcByNameCall);
iCode.WriteUint8L(aType);
iCode.WriteUint8L(anArgumentCount);
}
///////////////////////////////////////////////////////////////////
//
// COplModuleParser
//
///////////////////////////////////////////////////////////////////
void COplModuleParser::CallStatementL(TOplToken aToken)
//
// Can invoke something callable as a statement. Call it and drop the returned type.
//
{
TOplToken::TType returnType=CallL(aToken);
PCodeL(TPcode::EDrop);
iCode<<returnType;
}
void COplModuleParser::ProcCallPostambleL(const COplReferenceSymbol* aSymbol)
//
// Puts out the Pcode for the procedure call
//
{
PCodeL(TPcode::EProcCall);
iCode<<(COplSymbol*)aSymbol;
}
/////////////////////////////////////////////////////////////////////
//
// COplEvalParser
//
/////////////////////////////////////////////////////////////////////
void COplEvalParser::ProcCallPreambleL(const TDesC& aName,TOplToken::TType aType)
//
// Evaluator converts fred%: into @%("Fred"):
//
{
// Drop teh trailing %, & or $ off the proc name
TInt len=aName.Length();
if (aType!=TOplToken::EReal)
len-=1;
TPtrC strippedName=aName.Left(len);
// And put this out as a constant expression on the stack
ConstantReferenceL(TOplConstant(strippedName));
PCodeL(TPcode::EProcCallName); // Marks the name on the stack for the Munger's benefit
}
void COplEvalParser::ProcCallPostambleL(const COplReferenceSymbol* aSymbol)
//
//
//
{
COplCallSymbol& call=STATIC_CAST(COplCallSymbol&, aSymbol->Declaration());
PCodeProcByNameL(call.Type(),call.Signature().ArgumentCount());
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?