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 + -
显示快捷键?