bool Bass::executeInstruction(Instruction& i) { activeInstruction = &i; string s = i.statement; evaluateDefines(s); if(s.match("macro ?*(*) {") || s.match("global macro ?*(*) {")) { bool local = s.beginsWith("global ") == false; s.ltrim<1>("global "); s.trim<1>("macro ", ") {"); lstring p = s.split<1>("("); bool scoped = p(0).beginsWith("scope "); p(0).ltrim<1>("scope "); lstring a = p(1).empty() ? lstring{} : p(1).qsplit(",").strip(); setMacro(p(0), a, ip, scoped, local); ip = i.ip; return true; } if(s.match("define ?*(*)") || s.match("global define ?*(*)")) { bool local = s.beginsWith("global ") == false; s.ltrim<1>("global "); lstring p = s.trim<1>("define ", ")").split<1>("("); setDefine(p(0), p(1), local); return true; } if(s.match("evaluate ?*(*)") || s.match("global evaluate ?*(*)")) { bool local = s.beginsWith("global ") == false; s.ltrim<1>("global "); lstring p = s.trim<1>("evaluate ", ")").split<1>("("); setDefine(p(0), evaluate(p(1)), local); return true; } if(s.match("variable ?*(*)") || s.match("global variable ?*(*)")) { bool local = s.beginsWith("global ") == false; s.ltrim<1>("global "); lstring p = s.trim<1>("variable ", ")").split<1>("("); setVariable(p(0), evaluate(p(1)), local); return true; } if(s.match("if ?* {")) { s.trim<1>("if ", " {").strip(); bool match = evaluate(s, Evaluation::Strict); ifStack.append(match); if(match == false) { ip = i.ip; } return true; } if(s.match("} else if ?* {")) { if(ifStack.last()) { ip = i.ip; } else { s.trim<1>("} else if ", " {").strip(); bool match = evaluate(s, Evaluation::Strict); ifStack.last() = match; if(match == false) { ip = i.ip; } } return true; } if(s.match("} else {")) { if(ifStack.last()) { ip = i.ip; } else { ifStack.last() = true; } return true; } if(s.match("} endif")) { ifStack.removeLast(); return true; } if(s.match("while ?* {")) { s.trim<1>("while ", " {").strip(); bool match = evaluate(s, Evaluation::Strict); if(match == false) ip = i.ip; return true; } if(s.match("} endwhile")) { ip = i.ip; return true; } if(s.match("?*(*)")) { lstring p = string{s}.rtrim<1>(")").split<1>("("); lstring a = p(1).empty() ? lstring{} : p(1).qsplit(",").strip(); string name = {p(0), ":", a.size()}; //arity overloading if(auto macro = findMacro({name})) { struct Parameter { enum class Type : unsigned { Define, Variable } type; string name; string value; }; vector<Parameter> parameters; for(unsigned n = 0; n < a.size(); n++) { lstring p = macro().parameters(n).split<1>(" ").strip(); if(p.size() == 1) p.prepend("define"); if(p(0) == "define") parameters.append({Parameter::Type::Define, p(1), a(n)}); else if(p(0) == "string") parameters.append({Parameter::Type::Define, p(1), text(a(n))}); else if(p(0) == "evaluate") parameters.append({Parameter::Type::Define, p(1), evaluate(a(n))}); else if(p(0) == "variable") parameters.append({Parameter::Type::Variable, p(1), evaluate(a(n))}); else error("unsupported parameter type: ", p(0)); } StackFrame frame; stackFrame.append(frame); stackFrame.last().ip = ip; stackFrame.last().scoped = macro().scoped; if(macro().scoped) { scope.append(p(0)); } setDefine("#", {"_", macroInvocationCounter++}, true); for(auto& parameter : parameters) { if(parameter.type == Parameter::Type::Define) setDefine(parameter.name, parameter.value, true); if(parameter.type == Parameter::Type::Variable) setVariable(parameter.name, integer(parameter.value), true); } ip = macro().ip; return true; } } if(s.match("} endmacro")) { ip = stackFrame.last().ip; if(stackFrame.last().scoped) scope.removeLast(); stackFrame.removeLast(); return true; } if(assemble(s)) { return true; } evaluate(s); return true; }
UCHAR processIncludeFile( char *s ) { MACRODEF *m; struct _finddata_t finddata; NMHANDLE searchHandle; char *t, *p, *u; int c = 0; int i; if (!*s || *s == '#') { makeError(line, SYNTAX_NO_NAME); } if ((t = _tcspbrk(s,"\t#"))) { if (*t == '#') { c = *t; } *t = '\0'; if (!c) { for (u = t; *++u;) { // check for extra if (*u == '#') { break; // text on line } if (!WHITESPACE(*u)) { makeError(line, SYNTAX_UNEXPECTED_TOKEN, u); } } } } else { t = s + _tcslen(s); } // remove trailing white space while (t > s) { char *prev; prev = _tcsdec(s, t); if (!WHITESPACE(*prev)) break; t = prev; } *t = '\0'; if (*s == '<' && *(t-1) == '>') { char *pt; *--t = '\0'; p = removeMacros(++s); p = p == s ? makeString(s) : p; t = (m = findMacro("INCLUDE")) ? m->values->text : (char*) NULL; if (t != NULL) { // expand INCLUDE macro before passing it on char * pt1; pt1= makeString(t); pt = removeMacros(pt1); if (pt != pt1) { FREE(pt1); // we've got a new string, free old one } } else { pt = NULL; } if (!(u = searchPath(pt, p, &finddata, &searchHandle))) { makeError(line, CANT_OPEN_FILE, p); } if (pt) { FREE(pt); } FREE(p); s = u; } else { if (*s == '"' && *(t-1) == '"') { *--t = '\0'; ++s; } p = removeMacros(s); p = p == s ? makeString(s) : p; if (!findFirst(p, &finddata, &searchHandle)) { if (!_tcspbrk(p, "\\/:")) { //use C sematics for include for (i = incTop;i >= 0;i--) { t = (i == incTop) ? fName : incStack[i].name; if (!(t = getPath(t))) continue; u = (char *)allocate(_tcslen(t) + 1 + _tcslen(p) + 1); _tcscat(_tcscat(_tcscpy(u, t), PATH_SEPARATOR), p); if (findFirst(u, &finddata, &searchHandle)) { s = u; FREE(t); break; } FREE(t); FREE(u); } FREE(p); if (i < 0) { makeError(line, CANT_OPEN_FILE, s); } } else { makeError(line, CANT_OPEN_FILE, p); } } } for (i = 0; i < incTop; ++i) { // test for cycles if (!_tcsicmp(s,incStack[i].name)) { makeError(line, CYCLE_IN_INCLUDES, s); } } incStack[incTop].file = file; // push info on stack incStack[incTop].line = line; incStack[incTop++].name = fName; currentLine = 0; if (!(file = OpenValidateMakefile(s,"rt"))) { // read, text mode makeError(line,CANT_OPEN_FILE,s); } fName = makeString(s); line = 1; colZero = TRUE; // parser needs to see some kind of c = lgetc(); // newline to initialize it for this if ((colZero = (BOOL) !WHITESPACE(c))) { // file UngetTxtChr(c,file); line=0; // We did not start reading the file return(NEWLINE); } return(NEWLINESPACE); }
BOOL putMacro( char *name, char *value, UCHAR flags ) { MACRODEF *p; STRINGLIST *q; BOOL defined = FALSE; BOOL fSyntax = TRUE; // Convert path separators to the native path separator. // Do that with a copy of the original string so we don't change // the original. value = makeString(value); #if PLATFORM_UNIX char *tmp = value; while ((tmp = FindFirstPathSeparator(tmp))) { *tmp++ = PATH_SEPARATOR_CHAR; } #endif // PLATFORM_UNIX // Inherit macro definitions. Call removeMacros() to expand sub-macro // definitions. Must be done before macro is put in table, else // recursive definitions won't work. if (ON(flags, M_NON_RESETTABLE)) { if (*value) if ((putEnvStr(name,removeMacros(value)) == -1)) makeError(currentLine, OUT_OF_ENV_SPACE); } else if (fInheritUserEnv && OFF(gFlags, F1_USE_ENVIRON_VARS) && getenv(name) ) { if ((p = findMacro(name))) { // don't let user if (CANT_REDEFINE(p)) // redefine cmdline return(FALSE); // macros, MAKE, etc. } if ((putEnvStr(name,removeMacros(value)) == -1)) makeError(currentLine, OUT_OF_ENV_SPACE); } fInheritUserEnv = (BOOL)FALSE; if ((p = findMacro(name))) { // don't let user if (CANT_REDEFINE(p)) // redefine cmdline return(FALSE); // macros, MAKE, etc. } q = makeNewStrListElement(); q->text = value; if (!p) { p = makeNewMacro(); p->name = name; assert(p->flags == 0); assert(p->values == NULL); } else defined = TRUE; p->flags &= ~M_UNDEFINED; // Is no longer undefined p->flags |= flags; // Set flags to union of old and new prependItem((STRINGLIST**)&(p->values), (STRINGLIST*)q); if (!defined) insertMacro((STRINGLIST*)p); if (OFF(flags, M_LITERAL) && _tcschr(value, '$')) { // Check for cyclic Macro Definitions SET(p->flags, M_EXPANDING_THIS_ONE); // NULL -> don't build list fSyntax = findMacroValues(value, NULL, NULL, name, 1, 0, flags); CLEAR(p->flags, M_EXPANDING_THIS_ONE); } if (!fSyntax) { p->values = NULL; p->flags |= M_UNDEFINED; //return(FALSE); // return TRUE since p has been added to the macro table // Otherwise the caller may free name and value leaving // dangling pointers in the macro table. return(TRUE); } return(TRUE); }