/* * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Initial Developer of this code is David Baum. * Portions created by David Baum are Copyright (C) 1998 David Baum. * All Rights Reserved. * * Portions created by John Hansen are Copyright (C) 2005 John Hansen. * All Rights Reserved. * */ #include "Fragment.h" #include "BlockStmt.h" #include "RCX_Cmd.h" #include "Bytecode.h" #include "Program.h" #include "Symbol.h" #include "CallStmt.h" #include "DeclareStmt.h" #include "TaskIdExpr.h" #include "GotoStmt.h" #ifdef DEBUG //#ifdef __MWERKS__ #include //#endif // uncomment this to print the statement tree //#define DEBUG_DUMP_FRAGMENT #endif Fragment::Fragment(bool isTask, Symbol *name, Stmt *body) { fIsTask = isTask; fName = name; fBody = body; fNumber = gProgram->AddFragment(this); fTaskID = isTask ? fNumber : kNoTaskID; fStart.fIndex = kIllegalSrcIndex; fEnd.fIndex = kIllegalSrcIndex; } Fragment::Fragment(bool isTask) : fName(0), fBody(0) { fIsTask = isTask; fStart.fIndex = kIllegalSrcIndex; fEnd.fIndex = kIllegalSrcIndex; } Fragment::~Fragment() { delete fBody; } void Fragment::SetName(Symbol *name) { fName = name; fNumber = gProgram->AddFragment(this); fTaskID = fIsTask ? fNumber : kNoTaskID; } void Fragment::SetBody(Stmt *s) { // delete fBody; // this caused a call to a pure virtual function... fBody = s; } bool Fragment::AddArg(const Symbol *name, FunctionDef::ArgType type) { Arg a; for(size_t i=0; iNextVirtualVar(); switch(fArgs[i].fType) { case FunctionDef::kConstantArg: var |= kVirtualConstantFlag | kVirtualReadOnlyFlag; break; case FunctionDef::kConstRefArg: case FunctionDef::kSensorArg: var |= kVirtualReadOnlyFlag; break; case FunctionDef::kPointerArg: var |= kPointerFlag; break; case FunctionDef::kConstPtrArg: var |= kVirtualReadOnlyFlag | kPointerFlag; break; default: break; } fArgs[i].fVar = var; gProgram->DefineVar(fArgs[i].fName, var, false, ((fArgs[i].fType == FunctionDef::kPointerArg) || (fArgs[i].fType == FunctionDef::kConstPtrArg)), true); } } void Fragment::SetLocations(LocationNode *start, LocationNode *end) { fStart = start->GetLoc(); delete start; fEnd = end->GetLoc(); delete end; } void Fragment::AssignTaskID(int n) { if (n == fTaskID) return; if (fTaskID == kNoTaskID) fTaskID = n; else fTaskID = kMultiTaskID; } void Fragment::Emit(Bytecode &b) { b.AddSourceTag(RCX_SourceTag::kBegin, fStart); // bind TaskIdExprs to the actual task id // this must be done in Emit() rather than // Check() since subroutine trace isn't // complete until all fragments are checked TaskIdExpr::Patcher p(fTaskID); Apply(fBody, p); // resolve gotos - must be done in Emit() rather than // Check() since bytecode labels need to be generated GotoStmt::ResolveGotos(fBody, b); int rLabel = b.PushFlow(Bytecode::kReturnFlow); fBody->Emit(b); b.SetLabel(rLabel); b.PopFlow(Bytecode::kReturnFlow); b.ApplyFixups(); b.AddSourceTag(RCX_SourceTag::kEnd, fEnd); } #ifdef DEBUG using std::printf; class ParentChecker { public: bool operator()(Stmt *s); }; bool ParentChecker::operator()(Stmt *s) { Stmt *c; for(c=s->GetChildren(); c; c=c->GetNext()) { if (c->GetParent() != s) { printf("%s %08x\n", typeid(*s).name(), s); printf("Parent mistmatch: Found %08x expected %08x\n", c->GetParent(), s); } } return true; } #endif void Fragment::Check() { #ifdef DEBUG_DUMP_FRAGMENT DumpStmt(fBody); #endif CallStmt::Expander e(this); Apply(fBody, e); DeclareStmt::Binder b(0); Apply(fBody, b); #ifdef DEBUG ParentChecker p; Apply(fBody, p); #endif #ifdef DEBUG_DUMP_FRAGMENT DumpStmt(fBody); #endif }