bool Instruction::writesPredicate() const { for (int d = 0; defExists(d); ++d) if (getDef(d)->inFile(FILE_PREDICATE) || getDef(d)->inFile(FILE_FLAGS)) return true; return false; }
bool Instruction::canCommuteDefDef(const Instruction *i) const { for (int d = 0; defExists(d); ++d) for (int c = 0; i->defExists(c); ++c) if (getDef(d)->interfers(i->getDef(c))) return false; return true; }
bool Instruction::canCommuteDefSrc(const Instruction *i) const { for (int d = 0; defExists(d); ++d) for (int s = 0; i->srcExists(s); ++s) if (getDef(d)->interfers(i->getSrc(s))) return false; return true; }
void V3PreProcImp::define(FileLine* fl, const string& name, const string& value, const string& params, bool cmdline) { UINFO(4,"DEFINE '"<<name<<"' as '"<<value<<"' params '"<<params<<"'"<<endl); if (defExists(name)) { if (!(defValue(name)==value && defParams(name)==params)) { // Duplicate defs are OK fl->v3warn(REDEFMACRO,"Redefining existing define: "<<name<<", with different value: "<<value<<" "<<params); defFileline(name)->v3warn(REDEFMACRO,"Previous definition is here, with value: "<<defValue(name)<<" "<<defParams(name)); } undef(name); } m_defines.insert(make_pair(name, V3Define(fl, value, params, cmdline))); }
Instruction::~Instruction() { if (bb) { Function *fn = bb->getFunction(); bb->remove(this); fn->allInsns.remove(id); } for (int s = 0; srcExists(s); ++s) setSrc(s, NULL); // must unlink defs too since the list pointers will get deallocated for (int d = 0; defExists(d); ++d) setDef(d, NULL); }
string V3PreProcImp::removeDefines(const string& sym) { string val = "0_never_match"; string rtnsym = sym; for (int loopprevent=0; loopprevent<100; loopprevent++) { string xsym = rtnsym; if (xsym.substr(0,1)=="`") xsym.replace(0,1,""); if (defExists(xsym)) { val = defValue(xsym); if (val != rtnsym) rtnsym=val; // Prevent infinite loop if have `define X X else break; } else break; } return rtnsym; // NA }
unsigned int Instruction::defCount(unsigned int mask, bool singleFile) const { unsigned int i, n; if (singleFile) { unsigned int d = ffs(mask); if (!d) return 0; for (i = d--; defExists(i); ++i) if (getDef(i)->reg.file != getDef(d)->reg.file) mask &= ~(1 << i); } for (n = 0, i = 0; this->defExists(i); ++i, mask >>= 1) n += mask & 1; return n; }
Instruction * Instruction::clone(ClonePolicy<Function>& pol, Instruction *i) const { if (!i) i = new_Instruction(pol.context(), op, dType); #ifndef NDEBUG // non-conformant assert, so this is required assert(typeid(*i) == typeid(*this)); #endif pol.set<Instruction>(this, i); i->sType = sType; i->rnd = rnd; i->cache = cache; i->subOp = subOp; i->saturate = saturate; i->join = join; i->exit = exit; i->mask = mask; i->ftz = ftz; i->dnz = dnz; i->ipa = ipa; i->lanes = lanes; i->perPatch = perPatch; i->postFactor = postFactor; for (int d = 0; defExists(d); ++d) i->setDef(d, pol.get(getDef(d))); for (int s = 0; srcExists(s); ++s) { i->setSrc(s, pol.get(getSrc(s))); i->src(s).mod = src(s).mod; } i->cc = cc; i->predSrc = predSrc; i->flagsDef = flagsDef; i->flagsSrc = flagsSrc; return i; }
void Instruction::print() const { #define BUFSZ 512 const size_t size = BUFSZ; char buf[BUFSZ]; int s, d; size_t pos = 0; PRINT("%s", colour[TXT_INSN]); if (join) PRINT("join "); if (predSrc >= 0) { const size_t pre = pos; if (getSrc(predSrc)->reg.file == FILE_PREDICATE) { if (cc == CC_NOT_P) PRINT("not"); } else { PRINT("%s", CondCodeStr[cc]); } if (pos > pre) SPACE(); pos += getSrc(predSrc)->print(&buf[pos], BUFSZ - pos); PRINT(" %s", colour[TXT_INSN]); } if (saturate) PRINT("sat "); if (asFlow()) { PRINT("%s", operationStr[op]); if (asFlow()->indirect) PRINT(" ind"); if (asFlow()->absolute) PRINT(" abs"); if (op == OP_CALL && asFlow()->builtin) { PRINT(" %sBUILTIN:%i", colour[TXT_BRA], asFlow()->target.builtin); } else if (op == OP_CALL && asFlow()->target.fn) { PRINT(" %s%s:%i", colour[TXT_BRA], asFlow()->target.fn->getName(), asFlow()->target.fn->getLabel()); } else if (asFlow()->target.bb) PRINT(" %sBB:%i", colour[TXT_BRA], asFlow()->target.bb->getId()); } else { PRINT("%s ", operationStr[op]); if (op == OP_LINTERP || op == OP_PINTERP) PRINT("%s ", interpStr[ipa]); switch (op) { case OP_SUREDP: case OP_ATOM: if (subOp < ARRAY_SIZE(atomSubOpStr)) PRINT("%s ", atomSubOpStr[subOp]); break; case OP_LOAD: case OP_STORE: if (subOp < ARRAY_SIZE(ldstSubOpStr)) PRINT("%s ", ldstSubOpStr[subOp]); break; case OP_SUBFM: if (subOp < ARRAY_SIZE(subfmOpStr)) PRINT("%s ", subfmOpStr[subOp]); break; case OP_SHFL: if (subOp < ARRAY_SIZE(shflOpStr)) PRINT("%s ", shflOpStr[subOp]); break; case OP_PIXLD: if (subOp < ARRAY_SIZE(pixldOpStr)) PRINT("%s ", pixldOpStr[subOp]); break; case OP_RCP: case OP_RSQ: if (subOp < ARRAY_SIZE(rcprsqOpStr)) PRINT("%s ", rcprsqOpStr[subOp]); break; case OP_EMIT: if (subOp < ARRAY_SIZE(emitOpStr)) PRINT("%s ", emitOpStr[subOp]); break; default: if (subOp) PRINT("(SUBOP:%u) ", subOp); break; } if (perPatch) PRINT("patch "); if (asTex()) PRINT("%s %s$r%u $s%u %s", asTex()->tex.target.getName(), colour[TXT_MEM], asTex()->tex.r, asTex()->tex.s, colour[TXT_INSN]); if (postFactor) PRINT("x2^%i ", postFactor); PRINT("%s%s", dnz ? "dnz " : (ftz ? "ftz " : ""), DataTypeStr[dType]); } if (rnd != ROUND_N) PRINT(" %s", RoundModeStr[rnd]); if (defExists(1)) PRINT(" {"); for (d = 0; defExists(d); ++d) { SPACE(); pos += getDef(d)->print(&buf[pos], size - pos); } if (d > 1) PRINT(" %s}", colour[TXT_INSN]); else if (!d && !asFlow()) PRINT(" %s#", colour[TXT_INSN]); if (asCmp()) PRINT(" %s%s", colour[TXT_INSN], CondCodeStr[asCmp()->setCond]); if (sType != dType) PRINT(" %s%s", colour[TXT_INSN], DataTypeStr[sType]); for (s = 0; srcExists(s); ++s) { if (s == predSrc || src(s).usedAsPtr) continue; const size_t pre = pos; SPACE(); pos += src(s).mod.print(&buf[pos], BUFSZ - pos); if (pos > pre + 1) SPACE(); if (src(s).isIndirect(0) || src(s).isIndirect(1)) pos += getSrc(s)->asSym()->print(&buf[pos], BUFSZ - pos, getIndirect(s, 0), getIndirect(s, 1)); else pos += getSrc(s)->print(&buf[pos], BUFSZ - pos, sType); } if (exit) PRINT("%s exit", colour[TXT_INSN]); PRINT("%s", colour[TXT_DEFAULT]); buf[MIN2(pos, BUFSZ - 1)] = 0; INFO("%s (%u)\n", buf, encSize); }
int V3PreProcImp::getStateToken() { // Return the next state-determined token while (1) { next_tok: if (isEof()) return VP_EOF; int tok = getRawToken(); ProcState state = m_states.top(); // Most states emit white space and comments between tokens. (Unless collecting a string) if (tok==VP_WHITE && state !=ps_STRIFY) return (tok); if (tok==VP_BACKQUOTE && state !=ps_STRIFY) { tok = VP_TEXT; } if (tok==VP_COMMENT) { if (!m_off) { if (m_lexp->m_keepComments == KEEPCMT_SUB) { string rtn; rtn.assign(yyourtext(),yyourleng()); comment(rtn); // Need to insure "foo/**/bar" becomes two tokens insertUnreadback (" "); } else if (m_lexp->m_keepComments) { return (tok); } else { // Need to insure "foo/**/bar" becomes two tokens insertUnreadback (" "); } } // We're off or processed the comment specially. If there are newlines // in it, we also return the newlines as TEXT so that the linenumber // count is maintained for downstream tools for (size_t len=0; len<(size_t)yyourleng(); len++) { if (yyourtext()[len]=='\n') m_lineAdd++; } goto next_tok; } if (tok==VP_LINE) { addLineComment(m_lexp->m_enterExit); goto next_tok; } if (tok==VP_DEFREF_JOIN) { // Here's something fun and unspecified as yet: // The existance of non-existance of a base define changes `` expansion // `define QA_b zzz // `define Q1 `QA``_b // 1Q1 -> zzz // `define QA a // `Q1 -> a_b // Note parenthesis make this unambiguous // `define Q1 `QA()``_b // -> a_b // This may be a side effect of how `UNDEFINED remains as `UNDEFINED, // but it screws up our method here. So hardcode it. string name (yyourtext()+1,yyourleng()-1); if (defExists(name)) { // JOIN(DEFREF) // Put back the `` and process the defref UINFO(5,"```: define "<<name<<" exists, expand first\n"); m_defPutJoin = true; // After define, unputString("``"). Not now as would lose yyourtext() UINFO(5,"TOKEN now DEFREF\n"); tok = VP_DEFREF; } else { // DEFREF(JOIN) UINFO(5,"```: define "<<name<<" doesn't exist, join first\n"); // FALLTHRU, handle as with VP_SYMBOL_JOIN } } if (tok==VP_SYMBOL_JOIN || tok==VP_DEFREF_JOIN) { // not else if, can fallthru from above if() // a`` -> string doesn't include the ``, so can just grab next and continue string out (yyourtext(),yyourleng()); UINFO(5,"`` LHS:"<<out<<endl); // a``b``c can have multiple joins, so we need a stack m_joinStack.push(out); statePush(ps_JOIN); goto next_tok; } // Deal with some special parser states switch (state) { case ps_TOP: { break; } case ps_DEFNAME_UNDEF: // FALLTHRU case ps_DEFNAME_DEFINE: // FALLTHRU case ps_DEFNAME_IFDEF: // FALLTHRU case ps_DEFNAME_IFNDEF: // FALLTHRU case ps_DEFNAME_ELSIF: { if (tok==VP_SYMBOL) { m_lastSym.assign(yyourtext(),yyourleng()); if (state==ps_DEFNAME_IFDEF || state==ps_DEFNAME_IFNDEF) { bool enable = defExists(m_lastSym); UINFO(4,"Ifdef "<<m_lastSym<<(enable?" ON":" OFF")<<endl); if (state==ps_DEFNAME_IFNDEF) enable = !enable; m_ifdefStack.push(VPreIfEntry(enable,false)); if (!enable) parsingOff(); statePop(); goto next_tok; } else if (state==ps_DEFNAME_ELSIF) { if (m_ifdefStack.empty()) { error("`elsif with no matching `if\n"); } else { // Handle `else portion VPreIfEntry lastIf = m_ifdefStack.top(); m_ifdefStack.pop(); if (!lastIf.on()) parsingOn(); // Handle `if portion bool enable = !lastIf.everOn() && defExists(m_lastSym); UINFO(4,"Elsif "<<m_lastSym<<(enable?" ON":" OFF")<<endl); m_ifdefStack.push(VPreIfEntry(enable, lastIf.everOn())); if (!enable) parsingOff(); } statePop(); goto next_tok; } else if (state==ps_DEFNAME_UNDEF) { if (!m_off) { UINFO(4,"Undef "<<m_lastSym<<endl); undef(m_lastSym); } statePop(); goto next_tok; } else if (state==ps_DEFNAME_DEFINE) { // m_lastSym already set. stateChange(ps_DEFFORM); m_lexp->pushStateDefForm(); goto next_tok; } else fatalSrc("Bad case\n"); goto next_tok; } else if (tok==VP_TEXT) { // IE, something like comment between define and symbol if (!m_off) return tok; else goto next_tok; } else if (tok==VP_DEFREF) { // IE, `ifdef `MACRO(x): Substitue and come back here when state pops. break; } else { error((string)"Expecting define name. Found: "+tokenName(tok)+"\n"); goto next_tok; } } case ps_DEFFORM: { if (tok==VP_DEFFORM) { m_formals = m_lexp->m_defValue; if (debug()>=5) cout<<"DefFormals='"<<V3PreLex::cleanDbgStrg(m_formals)<<"'\n"; stateChange(ps_DEFVALUE); m_lexp->pushStateDefValue(); goto next_tok; } else if (tok==VP_TEXT) { // IE, something like comment in formals if (!m_off) return tok; else goto next_tok; } else { error((string)"Expecting define formal arguments. Found: "+tokenName(tok)+"\n"); goto next_tok; } } case ps_DEFVALUE: { static string newlines; newlines = "\n"; // Always start with trailing return if (tok == VP_DEFVALUE) { if (debug()>=5) cout<<"DefValue='"<<V3PreLex::cleanDbgStrg(m_lexp->m_defValue) <<"' formals='"<<V3PreLex::cleanDbgStrg(m_formals)<<"'\n"; // Add any formals string formals = m_formals; string value = m_lexp->m_defValue; // Remove returns // Not removing returns in values has two problems, // 1. we need to correct line numbers with `line after each substitution // 2. Substituting in " .... " with embedded returns requires \ escape. // This is very difficult in the presence of `", so we keep the \ before the newline. for (size_t i=0; i<formals.length(); i++) { if (formals[i] == '\n') { newlines += "\n"; } } for (size_t i=0; i<value.length(); i++) { if (value[i] == '\n') { newlines += "\n"; } } if (!m_off) { // Remove leading and trailing whitespace value = trimWhitespace(value, true); // Define it UINFO(4,"Define "<<m_lastSym<<" "<<formals <<" = '"<<V3PreLex::cleanDbgStrg(value)<<"'"<<endl); define(fileline(), m_lastSym, value, formals, false); } } else { string msg = string("Bad define text, unexpected ")+tokenName(tok)+"\n"; fatalSrc(msg); } statePop(); // DEFVALUE is terminated by a return, but lex can't return both tokens. // Thus, we emit a return here. yyourtext(newlines.c_str(), newlines.length()); return(VP_WHITE); } case ps_DEFPAREN: { if (tok==VP_TEXT && yyourleng()==1 && yyourtext()[0]=='(') { stateChange(ps_DEFARG); goto next_tok; } else { if (m_defRefs.empty()) fatalSrc("Shouldn't be in DEFPAREN w/o active defref"); V3DefineRef* refp = &(m_defRefs.top()); error((string)"Expecting ( to begin argument list for define reference `"+refp->name()+"\n"); statePop(); goto next_tok; } } case ps_DEFARG: { if (m_defRefs.empty()) fatalSrc("Shouldn't be in DEFARG w/o active defref"); V3DefineRef* refp = &(m_defRefs.top()); refp->nextarg(refp->nextarg()+m_lexp->m_defValue); m_lexp->m_defValue=""; UINFO(4,"defarg++ "<<refp->nextarg()<<endl); if (tok==VP_DEFARG && yyourleng()==1 && yyourtext()[0]==',') { refp->args().push_back(refp->nextarg()); stateChange(ps_DEFARG); m_lexp->pushStateDefArg(1); refp->nextarg(""); goto next_tok; } else if (tok==VP_DEFARG && yyourleng()==1 && yyourtext()[0]==')') { // Substitute in and prepare for next action // Similar code in non-parenthesized define (Search for END_OF_DEFARG) refp->args().push_back(refp->nextarg()); string out; if (!m_off) { out = defineSubst(refp); //NOP: out = m_preprocp->defSubstitute(out); } m_defRefs.pop(); refp=NULL; if (m_defRefs.empty()) { statePop(); if (!m_off) unputDefrefString(out); m_lexp->m_parenLevel = 0; } else { // Finished a defref inside a upper defref // Can't subst now, or // `define a(ign) x,y // foo(`a(ign),`b) would break because a contains comma refp = &(m_defRefs.top()); // We popped, so new top refp->nextarg(refp->nextarg()+m_lexp->m_defValue+out); m_lexp->m_defValue=""; m_lexp->m_parenLevel = refp->parenLevel(); statePop(); // Will go to ps_DEFARG, as we're under another define } goto next_tok; } else if (tok==VP_DEFREF) { // Expand it, then state will come back here // Value of building argument is data before the lower defref // we'll append it when we push the argument. break; } else if (tok==VP_SYMBOL || tok==VP_STRING || VP_TEXT || VP_WHITE) { string rtn; rtn.assign(yyourtext(),yyourleng()); refp->nextarg(refp->nextarg()+rtn); goto next_tok; } else { error((string)"Expecting ) or , to end argument list for define reference. Found: "+tokenName(tok)); statePop(); goto next_tok; } } case ps_INCNAME: { if (tok==VP_STRING) { statePop(); m_lastSym.assign(yyourtext(),yyourleng()); UINFO(4,"Include "<<m_lastSym<<endl); // Drop leading and trailing quotes. m_lastSym.erase(0,1); m_lastSym.erase(m_lastSym.length()-1,1); include(m_lastSym); goto next_tok; } else if (tok==VP_TEXT && yyourleng()==1 && yyourtext()[0]=='<') { // include <filename> stateChange(ps_INCNAME); // Still m_lexp->pushStateIncFilename(); goto next_tok; } else if (tok==VP_DEFREF || tok==VP_STRIFY) { // Expand it, then state will come back here break; } else { statePop(); error((string)"Expecting include filename. Found: "+tokenName(tok)+"\n"); goto next_tok; } } case ps_ERRORNAME: { if (tok==VP_STRING) { if (!m_off) { m_lastSym.assign(yyourtext(),yyourleng()); error(m_lastSym); } statePop(); goto next_tok; } else { error((string)"Expecting `error string. Found: "+tokenName(tok)+"\n"); statePop(); goto next_tok; } } case ps_JOIN: { if (tok==VP_SYMBOL || tok==VP_TEXT) { if (m_joinStack.empty()) fatalSrc("`` join stack empty, but in a ``"); string lhs = m_joinStack.top(); m_joinStack.pop(); UINFO(5,"`` LHS:"<<lhs<<endl); string rhs (yyourtext(),yyourleng()); UINFO(5,"`` RHS:"<<rhs<<endl); string out = lhs+rhs; UINFO(5,"`` Out:"<<out<<endl); unputString(out); statePop(); goto next_tok; } else if (tok==VP_EOF || tok==VP_WHITE || tok == VP_COMMENT || tok==VP_STRING) { error((string)"Expecting symbol to terminate ``; whitespace etc cannot follow ``. Found: "+tokenName(tok)+"\n"); statePop(); goto next_tok; } else { // `define, etc, fall through and expand. Pop back here. break; } } case ps_STRIFY: { if (tok==VP_STRIFY) { // Quote what's in the middle of the stringification // Note a `" MACRO_WITH(`") `" doesn't need to be handled (we don't need a stack) // That behavior isn't specified, and other simulators vary widely string out = m_strify; m_strify = ""; // Convert any newlines to spaces, so we don't get a multiline "..." without \ escapes // The spec is silent about this either way; simulators vary string::size_type pos; while ((pos=out.find("\n")) != string::npos) { out.replace(pos, 1, " "); } unputString((string)"\""+out+"\""); statePop(); goto next_tok; } else if (tok==VP_EOF) { error("`\" not terminated at EOF\n"); } else if (tok==VP_BACKQUOTE) { m_strify += "\\\""; goto next_tok; } else if (tok==VP_DEFREF) { // Spec says to expand macros inside `" // Substitue it into the stream, then return here break; } else { // Append token to eventual string m_strify.append(yyourtext(),yyourleng()); goto next_tok; } } default: fatalSrc("Bad case\n"); } // Default is to do top level expansion of some tokens switch (tok) { case VP_INCLUDE: if (!m_off) { statePush(ps_INCNAME); } goto next_tok; case VP_UNDEF: statePush(ps_DEFNAME_UNDEF); goto next_tok; case VP_DEFINE: // No m_off check here, as a `ifdef NEVER `define FOO(`endif) should work statePush(ps_DEFNAME_DEFINE); goto next_tok; case VP_IFDEF: statePush(ps_DEFNAME_IFDEF); goto next_tok; case VP_IFNDEF: statePush(ps_DEFNAME_IFNDEF); goto next_tok; case VP_ELSIF: statePush(ps_DEFNAME_ELSIF); goto next_tok; case VP_ELSE: if (m_ifdefStack.empty()) { error("`else with no matching `if\n"); } else { VPreIfEntry lastIf = m_ifdefStack.top(); m_ifdefStack.pop(); bool enable = !lastIf.everOn(); UINFO(4,"Else "<<(enable?" ON":" OFF")<<endl); m_ifdefStack.push(VPreIfEntry(enable, lastIf.everOn())); if (!lastIf.on()) parsingOn(); if (!enable) parsingOff(); } goto next_tok; case VP_ENDIF: UINFO(4,"Endif "<<endl); if (m_ifdefStack.empty()) { error("`endif with no matching `if\n"); } else { VPreIfEntry lastIf = m_ifdefStack.top(); m_ifdefStack.pop(); if (!lastIf.on()) parsingOn(); // parsingOn() really only enables parsing if // all ifdef's above this want it on } goto next_tok; case VP_DEFREF: { // m_off not right here, but inside substitution, to make this work: `ifdef NEVER `DEFUN(`endif) string name (yyourtext()+1,yyourleng()-1); UINFO(4,"DefRef "<<name<<endl); if (m_defPutJoin) { m_defPutJoin = false; unputString("``"); } if (m_defDepth++ > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) { error("Recursive `define substitution: `"+name); goto next_tok; } // substitute if (!defExists(name)) { // Not found, return original string as-is m_defDepth = 0; UINFO(4,"Defref `"<<name<<" => not_defined"<<endl); if (m_off) { goto next_tok; } else { return (VP_TEXT); } } else { string params = defParams(name); if (params=="0" || params=="") { // Found, as simple substitution if (m_off) { goto next_tok; } else { V3DefineRef tempref(name, ""); string out = defineSubst(&tempref); // Similar code in parenthesized define (Search for END_OF_DEFARG) //NOP: out = m_preprocp->defSubstitute(out); if (m_defRefs.empty()) { // Just output the substitution unputDefrefString(out); } else { // Inside another define. // Can't subst now, or // `define a x,y // foo(`a,`b) would break because a contains comma V3DefineRef* refp = &(m_defRefs.top()); refp->nextarg(refp->nextarg()+m_lexp->m_defValue+out); m_lexp->m_defValue=""; } goto next_tok; } } else { // Found, with parameters UINFO(4,"Defref `"<<name<<" => parameterized"<<endl); // The CURRENT macro needs the paren saved, it's not a property of the child macro if (!m_defRefs.empty()) m_defRefs.top().parenLevel(m_lexp->m_parenLevel); m_defRefs.push(V3DefineRef(name, params)); statePush(ps_DEFPAREN); m_lexp->pushStateDefArg(0); goto next_tok; } } fatalSrc("Bad case\n"); } case VP_ERROR: { statePush(ps_ERRORNAME); goto next_tok; } case VP_EOF: if (!m_ifdefStack.empty()) { error("`ifdef not terminated at EOF\n"); } return tok; case VP_UNDEFINEALL: if (!m_off) { UINFO(4,"Undefineall "<<endl); undefineall(); } goto next_tok; case VP_STRIFY: // We must expand macros in the body of the stringification // Then, when done, form a final string to return // (it could be used as a include filename, for example, so need the string token) statePush(ps_STRIFY); goto next_tok; case VP_SYMBOL: case VP_STRING: case VP_TEXT: { m_defDepth = 0; if (!m_off) return tok; else goto next_tok; } case VP_WHITE: // Handled at top of loop case VP_COMMENT: // Handled at top of loop case VP_DEFFORM: // Handled by state=ps_DEFFORM; case VP_DEFVALUE: // Handled by state=ps_DEFVALUE; default: fatalSrc((string)"Internal error: Unexpected token "+tokenName(tok)+"\n"); break; } return tok; } }