예제 #1
0
Value OrExpr::Evaluate(SymbolTable *scope, EvalContext& context, bool asbool)
{
	// Scope override; must do this for every expression that might contain an identifier
	if(this->scope != NULL)
		scope = this->scope;

	// Lowering of A or B:
	//  [A]
	//  [iftrue goto end]
	//  [B]
	//  label end:
	String* value = new String();

	string labelbase = context.GetUniqueLabelName();
	Anchor* endanchor = new Anchor(labelbase + ".end");

	// a
	value->Append( a->Evaluate(scope, context, true).ToCodeString() );
	// iftrue goto end:
	value->Code("1B 03 FF FF FF FF");
	value->AddReference(value->GetPos()-4, endanchor);
	// b
	value->Append( b->Evaluate(scope, context, true).ToCodeString() );
	// end:
	value->AddAnchor(endanchor);

	return Value(value);
}
예제 #2
0
Value AndExpr::Evaluate(SymbolTable *scope, EvalContext& context, bool asbool)
{
	// Scope override; must do this for every expression that might contain an identifier
	if(this->scope != NULL)
		scope = this->scope;

	// Lowering A and B:
	//  [A]
	//  [iffalse goto end]
	//  [B]
	//  label end:

	String* value = new String();

	// Create internal label
	string labelbase = context.GetUniqueLabelName();
	Anchor* endanchor = new Anchor(labelbase + ".end");

	// Evaluate the first operand
	value->Append( a->Evaluate(scope, context, true).ToCodeString() );

	// Add a jump to the end if the first operand is false
	value->Code("1B 02 FF FF FF FF");
	value->AddReference(value->GetPos()-4, endanchor);

	// TODO:
	//  Hm. I just realized that some boolean expressions (and and or) rely on reference
	//  resolution to operate correctly. Thus, it doesn't make sense to use them in ROM
	//  write statements at the moment, because ROM write statements occur after normal
	//  resolution, but without doing any resolution themselves. Perhaps ROM write statements
	//  should have a special resolution step to take care of stuff like this. (Perhaps
	//  the ROM data itself should be represented as a ByteChunk, with refs?)
	//  Anyway, don't worry about this for now, since using boolean expressions in a ROM
	//  write statement is not a very likely usage scenario.
	// UPDATE: 11/11/2008
	//  This issue has been fixed by moving the evaluation of ROM write subexpressions
	//  back to the evaluation pass of the compiler, and simply caching the results and
	//  resolving references in a later pass. However, it still might be worthwhile to
	//  consider alternative solutions; whole-ROM resolution seems interesting for example.

	// Evaluate the second operand
	value->Append( b->Evaluate(scope, context, true).ToCodeString() );

	// Set the position of the end label
	value->AddAnchor(endanchor);

	return Value(value);
}
예제 #3
0
Value Label::Evaluate(SymbolTable* scope, EvalContext &context, bool asbool)
{
	// The value of a label expression is an empty string
	// containing an anchor. The anchor was also registered
	// in the current scope in the PreTypecheck phase, so
	// other expressions can refer to this anchor.

	String* value = new String();

	Anchor* theAnchor = scope->LookupAnchor(name);

	if(!theAnchor) {
		Error("label evaluation lookup failed for '" + name + "' - probable internal compiler error!");
		return Value();
	}

	value->AddAnchor( theAnchor );

	return Value(value);
}
예제 #4
0
Value MenuExpr::Evaluate(SymbolTable* scope, EvalContext& context, bool asbool)
{
	if(this->scope != NULL)
		scope = this->scope;

	// Lowering a menu statement:
	// [19 02][option][02] - for each option
	// [1C 0C $cols][11][12]
	// [09 $num (statementjmps)]
	// [goto end]
	// [statement][goto end] - for each statement
	// label end:

	String* value = new String();

	// Create internal labels
	vector<Anchor*> anchors;
	string labelbase = context.GetUniqueLabelName();

	for(unsigned int i = 0; i < options.size(); ++i) {
		std::stringstream ss;
		ss << ".opt" << i;
		Anchor* a = new Anchor(labelbase + ss.str());
		anchors.push_back(a);
	}
	Anchor* endanchor = new Anchor(labelbase + ".end");

	// First, append the options between [19 02] and [02] codes
	for(unsigned int i = 0; i < options.size(); ++i) {
		value->Code("19 02");
		value->Append( options[i]->Evaluate(scope, context).ToCodeString() );
		value->Code("02");
	}

	// Next, append the option display commands
	// If we're only using two options, and no number of columns was specified,
	// use "1C 07", otherwise, use "1C 0C".
	if(options.size() == 2 && defcolumns)
		value->Code("1C 07");
	else
		value->Code("1C 0C");

	value->Byte(columns);// write exactly one byte for the column count
	value->Code("11 12");

	// Next, the multi-jump code
	value->Code("09");
	value->Byte(results.size());// write exactly one byte for the option count
	for(unsigned int i = 0; i < results.size(); ++i) {
		value->Code("FF FF FF FF");
		value->AddReference(value->GetPos() - 4, anchors[i]);
	}

	// Add a jump to the "default" option after the multi-jump, or end if no default
	value->Code("0A FF FF FF FF");
	if(defaultopt != -1)
		value->AddReference(value->GetPos() - 4, anchors[defaultopt]);
	else
		value->AddReference(value->GetPos() - 4, endanchor);


	// Finally, write out all the options, with a "goto end" after each
	// At each point we set the position of the relevant label.
	for(unsigned int i = 0; i < results.size(); ++i)
	{
		value->AddAnchor(anchors[i]);
		value->Append( results[i]->Evaluate(scope, context).ToCodeString() );

		// Add a "goto end" after every statement, in case it falls through
		value->Code("0A FF FF FF FF");
		value->AddReference(value->GetPos() - 4, endanchor);
	}

	// Last step: set position of the "end" label
	value->AddAnchor(endanchor);

	return Value(value);
}
예제 #5
0
Value IfExpr::Evaluate(SymbolTable *env, EvalContext& context, bool asbool)
{
	if(this->scope != NULL)
		env = this->scope;

	/*
	 * Lowering an if statement:
	 *
	 *  [condition]
	 *  [iffalse goto falselbl]
	 *  [thenstmt]
	 *  [goto endlbl]
	 * falselbl:
	 *  [elsestmt]
	 * endlbl:
	 */

	String* value = new String();
	
	// Create internal labels
	string labelbase = context.GetUniqueLabelName();
	Anchor* endanchor = new Anchor(labelbase + ".end");
	Anchor* falseanchor = new Anchor(labelbase + ".false");

	// First, we evaluate the condition
	Value cond_val = condition->Evaluate(env, context, true);

	// TODO: this might be an opportunity to do some typechecking on the returned value,
	// instead of just converting it to a string. Maybe some warnings would be appropriate?
	// (i.e., conditioning on a number value, which is almost always meaningless)

	// append cond_val to the output:
	value->Append(cond_val.ToCodeString());

	// Then, we output an "iffalse goto false" instruction, and register a jump reference
	value->Code("1B 02 FF FF FF FF");
	value->AddReference(value->GetSize() - 4, falseanchor);

	// Evaluate the "then" statement
	Value then_val = thenexpr->Evaluate(env, context);
	value->Append(then_val.ToCodeString());


	// Add a "goto end"
	// TODO: strictly speaking, we can dispense with this last goto when
	// there is no 'else' clause. We'll leave it here for now until we
	// get the first round of regression tests in place, and then we'll
	// update it along with the other evaluation refactoring.
	value->Code("0A FF FF FF FF");
	value->AddReference(value->GetPos() - 4, endanchor);

	// Set the position of the false anchor within the string
	value->AddAnchor(falseanchor);

	// Evaluate the "else" statement
	if(elseexpr) {
		Value else_val = elseexpr->Evaluate(env, context);
		value->Append(else_val.ToCodeString());
	}

	// Set the position of the "end" label
	value->AddAnchor(endanchor);

	return Value(value);
}