Value StringParser::Evaluate(SymbolTable* scope, EvalContext& context) { String* output = new String(); //ByteChunk* output = context.output; bool docodes = false; next(); while(current != '\0') { // Handle '$' escapes if(current == '{') { output->Append( expression(scope, context).ToCodeString() ); continue; } if(docodes) { // Break out of code mode if(current == ']') { next(); docodes = false; continue; } // consume whitespace if(current == ' ' || current == '\t' || current == '\n') { next(); continue; } int b = acceptbyte(); if(b == -1) Warning(string("invalid control code bytes ignored"),0,0); else output->Byte(b); next(); } else { if(current == '/') { output->Byte(16); output->Byte(5); } else if(current == '|') { output->Byte(16); output->Byte(15); } else if(current == '[') { docodes = true; } else { // Default: output->Char(current); } next(); continue; } } return Value(output); }
Value BoundedExpr::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; // TODO: there really has to be a better way to handle these scope overrides. // Having to put this if statement at the top of certain evaluate methods is kludgy. // Probably the logic for deciding the evaluation scope of a node should be at // a higher level, and all nodes should have their scope of evaluation set that way. String* value = new String(); Value expr_val = expr->Evaluate(scope, context); int pos; if(index < 0) pos = 0; else pos = size * index; try { // We've specified that any out-of-range access should be filled in // with zeroes, so we do a bit of bounds checking here String s = expr_val.ToCodeString(); int over = std::max(0, pos + size - (signed)s.GetSize()); int valid_size = std::max(0, size - over); if(valid_size > 0) { // We really ought to make a "substring constructor" -- // we do this fairly often and it involves an unfortunate // amount of copying. *value = s.Substring(pos, valid_size); } for(int i = 0; i < size - valid_size; ++i) value->Byte(0); } catch(Exception& e) { Error(e.GetMessage()); } return Value(value); }
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); }