#include "Array.h" #include "errors.h" #include "utils.h" #include "graph_calls.h" #include "SgUtils.h" #include "../DirectiveProcessing/directive_parser.h" #include "../DirectiveProcessing/directive_omp_parser.h" #include "../LoopAnalyzer/loop_analyzer.h" using namespace std; extern int ignoreIO; extern map> tableOfUniqNamesByArray; static set> checkedArraysForWrongLocation; static bool findOmpThreadPrivDecl(SgStatement* st, map>& ompThreadPrivate, SgSymbol* toFind) { auto it = ompThreadPrivate.find(st); if (it == ompThreadPrivate.end()) { it = ompThreadPrivate.insert(it, make_pair(st, set())); SgStatement* lastN = st->lastNodeOfStmt(); set dummy; do { st = st->lexNext(); auto res = parseOmpInStatement(st, dummy); for (auto& dir : res) for (auto& var : dir.threadPrivVars) it->second.insert(var); } while (st != lastN && !isSgExecutableStatement(st) && st->variant() != CONTAINS_STMT); } if (it->second.find(toFind->identifier()) != it->second.end()) return true; else return false; } static bool hasAssingOpInDecl(SgSymbol* symb) { vector allDecls; SgStatement* decl = declaratedInStmt(symb, &allDecls); for (auto& elem : allDecls) { if (elem->variant() == VAR_DECL_90) { SgExpression* list = elem->expr(0); while (list) { if (list->lhs()->variant() == ASSGN_OP) if (list->lhs()->lhs()->symbol() && OriginalSymbol(list->lhs()->lhs()->symbol()) == symb) return true; list = list->rhs(); } } } return false; } static string getNameWithScope(SgStatement* scope, const string& currFunctionName) { if (scope && isSgProgHedrStmt(scope) && scope->symbol()->identifier() != currFunctionName) return scope->symbol()->identifier(); else return currFunctionName; } struct findInfo { findInfo(const string fName, SgExpression* ex, int parN, bool isWrite) : fName(fName), ex(ex), parN(parN), isWrite(isWrite) { } SgExpression* ex; string fName; int parN; bool isWrite; }; static void findArrayRefs (SgExpression* ex, SgStatement* st, string fName, int parN, bool isWrite, const map>& commonBlocks, map, pair>& declaredArrays, map>>& declaratedArraysSt, const set& privates, const set& deprecatedByIO, bool isExecutable, const string& currFunctionName, const vector& inRegion, const set& funcParNames, map>& ompThreadPrivate, const map& distrStateFromGUI, const bool saveAllLocals, map>& currMessages, int& errorCount) { const string globalFile = current_file->filename(); const set filesInProj = getAllFilesInProject(); if (ex == NULL) return; stack queue; queue.push(findInfo(fName, ex, parN, isWrite)); while (!queue.empty()) { const findInfo& curQ = queue.top(); ex = curQ.ex; fName = curQ.fName; parN = curQ.parN; isWrite = curQ.isWrite; queue.pop(); if (isArrayRef(ex)) { SgSymbol* symb = OriginalSymbol(ex->symbol()); const bool inDataStat = (symb->attributes() & DATA_BIT) != 0 || ((ex->symbol())->attributes() & DATA_BIT); checkNull(symb->type(), convertFileName(__FILE__).c_str(), __LINE__); const int typeSize = getSizeOfType(symb->type()->baseType()); if (typeSize == 0) { //__spf_print(1, "Wrong type size for array %s\n", symb->identifier()); //printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } SgStatement* decl = declaratedInStmt(symb); if (decl->variant() == DVM_VAR_DECL || decl->variant() == HPF_TEMPLATE_STAT) { const string tmp(decl->unparse()); if (tmp.find("!DVM$ TEMPLATE") != string::npos) { auto sTemp = symb->identifier(); tuple uniqKey; bool found = false; for (auto& elem : declaredArrays) { if (elem.second.first->GetShortName() == sTemp) { uniqKey = elem.first; found = true; } } if (found) { auto itDecl = declaratedArraysSt.find(decl); if (itDecl == declaratedArraysSt.end()) itDecl = declaratedArraysSt.insert(itDecl, make_pair(decl, set>())); itDecl->second.insert(uniqKey); return; } } } auto uniqKey = getUniqName(commonBlocks, decl, symb); SgStatement* scope = symb->scope(); pair arrayLocation; string typePrefix = ""; while (scope && scope->variant() == STRUCT_DECL) { if (typePrefix == "") typePrefix = scope->symbol()->identifier(); else typePrefix += scope->symbol()->identifier() + string("::"); scope = scope->controlParent(); } if ((ex->symbol() && symb != ex->symbol()) || (scope && scope->variant() == MODULE_STMT)) { if (scope) { string modName = scope->symbol()->identifier(); arrayLocation = make_pair(DIST::l_MODULE, (typePrefix == "") ? modName : modName + "::" + typePrefix); } else //TODO: find module name with another way arrayLocation = make_pair(DIST::l_MODULE, "UNREC_MODULE_NAME"); } else if (get<1>(uniqKey).find("common_") != string::npos) arrayLocation = make_pair(DIST::l_COMMON, get<1>(uniqKey).substr(strlen("common_"))); else if (funcParNames.find(symb->identifier()) != funcParNames.end()) arrayLocation = make_pair(DIST::l_PARAMETER, getNameWithScope(scope, currFunctionName)); else { if (saveAllLocals || ((symb->attributes() & SAVE_BIT) != 0) || hasAssingOpInDecl(symb)) arrayLocation = make_pair(DIST::l_LOCAL_SAVE, getNameWithScope(scope, currFunctionName)); else arrayLocation = make_pair(DIST::l_LOCAL, getNameWithScope(scope, currFunctionName)); } auto itNew = declaredArrays.find(uniqKey); if (itNew == declaredArrays.end()) { DIST::Array* arrayToAdd = new DIST::Array(getShortName(uniqKey), symb->identifier(), ((SgArrayType*)(symb->type()))->dimension(), getUniqArrayId(), decl->fileName(), decl->lineNumber(), arrayLocation, new Symbol(symb), findOmpThreadPrivDecl(scope, ompThreadPrivate, symb), false, false, inRegion, typeSize, sharedMemoryParallelization ? DIST::NO_DISTR : DIST::DISTR); itNew = declaredArrays.insert(itNew, make_pair(uniqKey, make_pair(arrayToAdd, new DIST::ArrayAccessInfo()))); vector> sizes; map> arrayLinksByFuncCallsNotReady; map> allFuncInfoNoReady; auto sizesExpr = getArraySizes(sizes, symb, decl, arrayLinksByFuncCallsNotReady, allFuncInfoNoReady); arrayToAdd->SetSizes(sizes); arrayToAdd->SetSizesExpr(sizesExpr); tableOfUniqNamesByArray[arrayToAdd] = uniqKey; } else // check the same location from include! { auto prevLocation = itNew->second.first->GetLocation(); if (prevLocation != arrayLocation) { if (checkedArraysForWrongLocation.find(uniqKey) == checkedArraysForWrongLocation.end()) { checkedArraysForWrongLocation.insert(uniqKey); __spf_print(1, "can not change declaration area of array '%s' on line %d\n", symb->identifier(), st->lineNumber()); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Array '%s' has declaration area conflict, it might be worth applying the Include inlining pass", to_wstring(symb->identifier()).c_str()); __spf_printToLongBuf(messageR, R184, to_wstring(symb->identifier()).c_str()); currMessages[st->fileName()].push_back(Messages(ERROR, st->lineNumber(), messageR, messageE, 1061)); } errorCount++; } } if ((symb->attributes() & EQUIVALENCE_BIT) != 0) itNew->second.first->SetEquvalence(true); for (auto& reg : inRegion) itNew->second.first->SetRegionPlace(reg); const auto oldVal = itNew->second.first->GetDistributeFlagVal(); bool isArrayInModule = (itNew->second.first->GetLocation().first == DIST::l_MODULE); if (oldVal == DIST::DISTR || oldVal == DIST::NO_DISTR) { if (itNew->second.first->IsOmpThreadPrivate()) itNew->second.first->SetDistributeFlag(DIST::SPF_PRIV); else if (deprecatedByIO.find(symb->identifier()) != deprecatedByIO.end()) itNew->second.first->SetDistributeFlag(DIST::IO_PRIV); else if (isArrayInModule || privates.find(symb->identifier()) != privates.end()) { //check in module if (itNew->second.first->GetLocation().first == DIST::l_MODULE) { for (auto& data : getAttributes(decl, set{ SPF_ANALYSIS_DIR })) { set privatesS; fillPrivatesFromComment(new Statement(data), privatesS); if (privatesS.find(symb->identifier()) != privatesS.end()) { itNew->second.first->SetDistributeFlag(DIST::SPF_PRIV); break; } } auto prev = decl->lexPrev(); checkNull(prev, convertFileName(__FILE__).c_str(), __LINE__); set privatesS; fillPrivatesFromComment(new Statement(prev), privatesS); if (privatesS.find(symb->identifier()) != privatesS.end()) itNew->second.first->SetDistributeFlag(DIST::SPF_PRIV); } else itNew->second.first->SetDistributeFlag(DIST::SPF_PRIV); } else if (isSgConstantSymb(symb) || inDataStat) itNew->second.first->SetDistributeFlag(DIST::SPF_PRIV); else { auto it = distrStateFromGUI.find(itNew->second.first->GetIndepUniqName()); if (it != distrStateFromGUI.end()) { if (it->second != oldVal) { itNew->second.first->SetDistributeFlag((DIST::distFlag)it->second); __spf_print(1, "change flag for array from cache '%s': %d -> %d\n", it->first.c_str(), oldVal, it->second); } } else itNew->second.first->SetDistributeFlag(DIST::DISTR); } } if (typeSize == 0) // unknown itNew->second.first->SetDistributeFlag(DIST::SPF_PRIV); if (!isExecutable) itNew->second.first->AddDeclInfo(make_pair(st->fileName(), st->lineNumber()), filesInProj, globalFile, new Symbol(symb)); if (isExecutable) { if (st->variant() != ALLOCATE_STMT && st->variant() != DEALLOCATE_STMT) { itNew->second.second->AddAccessInfo(st->fileName(), make_pair(st->lineNumber(), isWrite ? 1 : 0), fName, parN); itNew->second.first->AddUsagePlace(st->fileName(), st->lineNumber()); } } auto itDecl = declaratedArraysSt.find(decl); if (itDecl == declaratedArraysSt.end()) itDecl = declaratedArraysSt.insert(itDecl, make_pair(decl, set>())); itDecl->second.insert(uniqKey); if (decl->variant() == DVM_VAR_DECL || decl->variant() == HPF_TEMPLATE_STAT) { const string tmp(decl->unparse()); if (tmp.find("!DVM$ TEMPLATE") != string::npos) { itNew->second.first->SetTemplateFlag(true); //TODO: analyze align mapping for (int z = 0; z < itNew->second.first->GetDimSize(); ++z) itNew->second.first->SetMappedDim(z); } } } if (ex->variant() == FUNC_CALL) { SgFunctionCallExp* funcExp = (SgFunctionCallExp*)ex; const string fName = funcExp->funName()->identifier(); bool intr = (isIntrinsicFunctionName(fName.c_str()) == 1); for (int z = 0; z < funcExp->numberOfArgs(); ++z) { //assume all arguments of function as OUT, except for inctrinsics bool isWriteN = intr ? false : true; //need to correct W/R usage with GraphCall map later findArrayRefs(funcExp->arg(z), st, fName, z, isWriteN, commonBlocks, declaredArrays, declaratedArraysSt, privates, deprecatedByIO, isExecutable, currFunctionName, inRegion, funcParNames, ompThreadPrivate, distrStateFromGUI, saveAllLocals, currMessages, errorCount); } } else { bool isWriteN = false; if (ex->lhs()) queue.push(findInfo("", ex->lhs(), -1, isWriteN)); if (ex->rhs()) queue.push(findInfo("", ex->rhs(), -1, isWriteN)); //findArrayRefs(ex->lhs(), st, "", -1, isWriteN, commonBlocks, declaredArrays, declaratedArraysSt, privates, deprecatedByIO, isExecutable, currFunctionName, inRegion, funcParNames, ompThreadPrivate, distrStateFromGUI, saveAllLocals, currMessages, errorCount); //findArrayRefs(ex->rhs(), st, "", -1, isWriteN, commonBlocks, declaredArrays, declaratedArraysSt, privates, deprecatedByIO, isExecutable, currFunctionName, inRegion, funcParNames, ompThreadPrivate, distrStateFromGUI, saveAllLocals, currMessages, errorCount); } } } static void findArrayRefInIO(SgExpression* ex, set& deprecatedByIO, SgStatement* st, map>& currMessages) { if (ex) { if (ex->variant() == ARRAY_REF) { auto symb = ex->symbol(); if (symb->type()) { if (symb->type()->variant() == T_ARRAY) { auto found = deprecatedByIO.find(OriginalSymbol(symb)->identifier()); if (found == deprecatedByIO.end()) { deprecatedByIO.insert(found, OriginalSymbol(symb)->identifier()); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Array '%s' can not be distributed because of DVM's I/O constraints", to_wstring(symb->identifier()).c_str()); __spf_printToLongBuf(messageR, R68, to_wstring(symb->identifier()).c_str()); currMessages[st->fileName()].push_back(Messages(WARR, st->lineNumber(), messageR, messageE, 1037)); __spf_print(1, "Array '%s' at line %d can not be distributed because of DVM's I/O constraints\n", symb->identifier(), st->lineNumber()); } } } } findArrayRefInIO(ex->lhs(), deprecatedByIO, st, currMessages); findArrayRefInIO(ex->rhs(), deprecatedByIO, st, currMessages); } } static void findReshape(SgStatement* st, set& privates, map>& currMessages) { if (st->variant() == ASSIGN_STAT) { SgExpression* exL = st->expr(0); SgExpression* exR = st->expr(1); if (exR->variant() == FUNC_CALL && exL->variant() == ARRAY_REF) { if (exR->symbol()->identifier() == string("reshape")) { if (privates.find(exL->symbol()->identifier()) == privates.end()) { privates.insert(exL->symbol()->identifier()); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Array '%s' can not be distributed because of RESHAPE", to_wstring(exL->symbol()->identifier()).c_str()); __spf_printToLongBuf(messageR, R90, to_wstring(exL->symbol()->identifier()).c_str()); currMessages[st->fileName()].push_back(Messages(NOTE, st->lineNumber(), messageR, messageE, 1047)); } } } } } static void findConstructorRef(SgStatement* st, set& privates, map>& currMessages) { if (st->variant() == ASSIGN_STAT) { SgExpression* exL = st->expr(0); SgExpression* exR = st->expr(1); if (exR->variant() == CONSTRUCTOR_REF && exL->variant() == ARRAY_REF) { if (privates.find(exL->symbol()->identifier()) == privates.end()) { privates.insert(exL->symbol()->identifier()); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"Array '%s' can not be distributed because of initializer list", to_wstring(exL->symbol()->identifier()).c_str()); __spf_printToLongBuf(messageR, R164, to_wstring(exL->symbol()->identifier()).c_str()); currMessages[st->fileName()].push_back(Messages(NOTE, st->lineNumber(), messageR, messageE, 1047)); } } } } static void addPrivates(SgStatement* st, set& privates, map>& reductions, map>>& reductionsLoc) { //after SPF preprocessing for (auto& data : getAttributes(st, set{ SPF_ANALYSIS_DIR })) { set privatesS; fillPrivatesFromComment(new Statement(data), privatesS); fillReductionsFromComment(new Statement(data), reductions); fillReductionsFromComment(new Statement(data), reductionsLoc); for (auto& elem : privatesS) privates.insert(elem->GetOriginal()->identifier()); } //before SPF preprocessing if (st->variant() == SPF_ANALYSIS_DIR) { set privatesS; fillPrivatesFromComment(new Statement(st), privatesS); fillReductionsFromComment(new Statement(st), reductions); fillReductionsFromComment(new Statement(st), reductionsLoc); for (auto& elem : privatesS) privates.insert(elem->GetOriginal()->identifier()); } } int getAllDeclaredArrays(SgFile* file, map, pair>& declaredArrays, map>>& declaratedArraysSt, map>& currMessages, const vector& regions, const map& distrStateFromGUI) { int countErrors = 0; vector modules; findModulesInFile(file, modules); map> privatesByModule; for (auto& mod : modules) { const string modName = mod->symbol()->identifier(); privatesByModule[modName] = set(); auto it = privatesByModule.find(modName); for (SgStatement* iter = mod; iter != mod->lastNodeOfStmt(); iter = iter->lexNext()) { if (iter->variant() == CONTAINS_STMT) break; //after SPF preprocessing for (auto& data : getAttributes(iter, set{ SPF_ANALYSIS_DIR })) fillPrivatesFromComment(new Statement(data), it->second); //before SPF preprocessing if (iter->variant() == SPF_ANALYSIS_DIR) fillPrivatesFromComment(new Statement(iter), it->second); } } map> ompThreadPrivate; for (int i = 0; i < file->numberOfFunctions(); ++i) { bool saveAllLocals = false; SgStatement* st = file->functions(i); SgStatement* lastNode = st->lastNodeOfStmt(); map> commonBlocks; const string currFunctionName = st->symbol()->identifier(); getCommonBlocksRef(commonBlocks, st, lastNode); set privates; set deprecatedByIO; map> reductions; map>> reductionsLoc; set funcParNames; if (st->variant() != PROG_HEDR) { SgProcHedrStmt* func = (SgProcHedrStmt*)st; for (int z = 0; z < func->numberOfParameters(); ++z) funcParNames.insert(func->parameter(z)->identifier()); if (func->nameWithContains() != func->name().identifier()) // added contains args { SgProcHedrStmt* cp = (SgProcHedrStmt*)func->controlParent(); checkNull(cp, convertFileName(__FILE__).c_str(), __LINE__); for (int z = 0; z < cp->numberOfParameters(); ++z) funcParNames.insert(cp->parameter(z)->identifier()); } } for (SgStatement* iter = st; iter != lastNode; iter = iter->lexNext()) { if (iter->variant() == CONTAINS_STMT) break; addPrivates(iter, privates, reductions, reductionsLoc); if (iter->variant() == USE_STMT) fillFromModule(iter->symbol(), privatesByModule, privates); if (iter->variant() == SAVE_DECL) if (!iter->expr(0) && !iter->expr(1) && !iter->expr(2)) saveAllLocals = true; } for (SgStatement* iter = st; iter != lastNode; iter = iter->lexNext()) { if (iter->variant() == CONTAINS_STMT) break; findReshape(iter, privates, currMessages); findConstructorRef(iter, privates, currMessages); } SgStatement* tmpModFind = st; while (tmpModFind->variant() != GLOBAL) { tmpModFind = tmpModFind->controlParent(); if (tmpModFind->variant() == MODULE_STMT) fillFromModule(tmpModFind->symbol(), privatesByModule, privates); } SgStatement* currF = st; SgStatement* contains = isSgProgHedrStmt(currF->controlParent()); if (contains) { for (SgStatement* loc = contains; loc; loc = loc->lexNext()) { if (isSgExecutableStatement(loc)) break; if (loc->variant() == CONTAINS_STMT) break; if (loc->variant() == USE_STMT) fillFromModule(loc->symbol(), privatesByModule, privates); } } for (auto& elem : reductions) for (auto& setElem : elem.second) privates.insert(setElem->identifier()); for (auto& elem : reductionsLoc) { for (auto& setElem : elem.second) { privates.insert(get<0>(setElem)->identifier()); privates.insert(get<1>(setElem)->identifier()); } } //analyze IO operations if (!ignoreIO) { for (SgStatement* iter = st; iter != lastNode; iter = iter->lexNext()) { if (iter->variant() == CONTAINS_STMT) break; SgInputOutputStmt* stIO = isSgInputOutputStmt(iter); set currRegs = getAllRegionsByLine(regions, iter->fileName(), iter->lineNumber()); if (stIO && currRegs.size()) // deprecate to distribute arrays only in regions { int countOfItems = 0; for (SgExpression* items = stIO->itemList(); items; items = items->rhs(), ++countOfItems); //TODO: need to add more checkers! if (countOfItems > 1) { for (SgExpression* items = stIO->itemList(); items; items = items->rhs()) findArrayRefInIO(items->lhs(), deprecatedByIO, stIO, currMessages); } else if (countOfItems == 1) { auto list = stIO->specList(); bool ok = true; //exclude FMT='format' while (list) { if (list->lhs() && list->lhs()->variant() == SPEC_PAIR) { auto ex = list->lhs(); if (ex->lhs() && ex->rhs()) { if (ex->lhs()->variant() == KEYWORD_VAL) { SgKeywordValExp* key = (SgKeywordValExp*)(ex->lhs()); if (key->value() == string("fmt")) if (ex->rhs()->variant() == STRING_VAL) ok = false; } } } if (!ok) break; list = list->rhs(); } //check A(i,j) for example auto item = stIO->itemList()->lhs(); if (item->rhs() || item->lhs()) ok = false; if (!ok) findArrayRefInIO(item, deprecatedByIO, stIO, currMessages); } } } } while (st != lastNode) { if (st->variant() == CONTAINS_STMT) break; if (!isSPF_stat(st) && !isDVM_stat(st)) { set currRegs = getAllRegionsByLine(regions, st->fileName(), st->lineNumber()); vector regNames; for (auto& reg : currRegs) regNames.push_back(reg->GetName()); if (regNames.size() == 0) regNames.push_back("default"); if (st->variant() == PROC_STAT) { SgCallStmt* funcExp = (SgCallStmt*)st; const string fName = funcExp->symbol()->identifier(); for (int z = 0; z < funcExp->numberOfArgs(); ++z) { findArrayRefs(funcExp->arg(z), st, fName, z, true, commonBlocks, declaredArrays, declaratedArraysSt, privates, deprecatedByIO, isSgExecutableStatement(st) ? true : false, currFunctionName, regNames, funcParNames, ompThreadPrivate, distrStateFromGUI, saveAllLocals, currMessages, countErrors); } } else { for (int i = 0; i < 3; ++i) findArrayRefs(st->expr(i), st, "", -1, (st->variant() == ASSIGN_STAT && i == 0) ? true : false, commonBlocks, declaredArrays, declaratedArraysSt, privates, deprecatedByIO, isSgExecutableStatement(st) ? true : false, currFunctionName, regNames, funcParNames, ompThreadPrivate, distrStateFromGUI, saveAllLocals, currMessages, countErrors); } } st = st->lexNext(); } } //preprocess only module declaration for (auto& mod : modules) { SgStatement* st = mod->lexNext(); SgStatement* lastNode = mod->lastNodeOfStmt(); map> commonBlocks; set privates; set deprecatedByIO; set funcParNames; fillFromModule(st->symbol(), privatesByModule, privates); while (st != lastNode) { if (st->variant() == CONTAINS_STMT) break; if (!isSPF_stat(st) && !isDVM_stat(st)) { //TODO: set clear regions for modules set currRegs = getAllRegionsByLine(regions, st->fileName(), st->lineNumber()); vector regNames; for (auto& reg : currRegs) regNames.push_back(reg->GetName()); if (regNames.size() == 0) regNames.push_back("default"); for (int i = 0; i < 3; ++i) findArrayRefs(st->expr(i), st, "", -1, false, commonBlocks, declaredArrays, declaratedArraysSt, privates, deprecatedByIO, false, "NULL", regNames, funcParNames, ompThreadPrivate, distrStateFromGUI, false, currMessages, countErrors); } st = st->lexNext(); } } //preprocess only block data declaration for (SgStatement* st = file->firstStatement()->lexNext(); st; st = st->lastNodeOfStmt(), st = st->lexNext()) { if (st->variant() == BLOCK_DATA) { SgStatement* last = st->lastNodeOfStmt(); SgStatement* curr = st; map> commonBlocks; getCommonBlocksRef(commonBlocks, st, last); set privates; set deprecatedByIO; set funcParNames; string blockName = "BLOCK DATA"; if (st->symbol()) blockName = st->symbol()->identifier(); while (curr && curr != last) { //TODO: set clear regions for block data set currRegs = getAllRegionsByLine(regions, curr->fileName(), curr->lineNumber()); vector regNames; for (auto& reg : currRegs) regNames.push_back(reg->GetName()); if (regNames.size() == 0) regNames.push_back("default"); for (int i = 0; i < 3; ++i) findArrayRefs(curr->expr(i), curr, "", -1, false, commonBlocks, declaredArrays, declaratedArraysSt, privates, deprecatedByIO, false, blockName, regNames, funcParNames, ompThreadPrivate, distrStateFromGUI, false, currMessages, countErrors); curr = curr->lexNext(); } } } return countErrors; }