static SymPtr FieldReference(SymPtr clas) { SymPtr field,parent; char *fieldname; SkipToken(tPERIOD); fieldname = GetIdent(); /* lookup field in class and parents */ parent=clas; while( parent!=NULL ) { field = SymFindLocal(fieldname,parent); if( field!=NULL ) break; parent = parent->super; } if( field==NULL ) { compileError("field '%s' not found",fieldname); return NULL; } field->flags |= SYM_FIELD; /* MCC */ if( field->flags&SYM_PRIVATE ) { compileError("attempt to access private field '%s'",fieldname); return NULL; } if( field->flags&SYM_PROTECTED && !in_class ) { compileError("attempt to access protected field '%s'",fieldname); return NULL; } NextToken(); if( is_func_kind(field) ) { return field; } if( is_global_kind(clas) ) { vm_genI(op_getglobal,clas->num); } else if( is_local_kind(clas) ) { vm_genI(op_getlocal,clas->num); } return field; }
static SymPtr LookupIdent(char **name) { SymPtr sym=NULL,parent; /* check this class only */ if( in_class && Token==tSELF ) { SkipToken(tSELF); SkipToken(tPERIOD); *name = GetIdent(); sym = SymFindLevel(*name,(SymGetScope()-1)); } /* check super class only */ else if( in_class && Token==tSUPER && base_class->super!=NULL ) { SkipToken(tSUPER); SkipToken(tPERIOD); *name = GetIdent(); sym = SymFindLocal(*name,base_class->super); if( sym!=NULL && sym->flags&SYM_PRIVATE ) { compileError("attempt to access private field '%s'",*name); NextToken(); return COMPILE_ERROR; } } /* check all super classes */ else if( in_class ) { *name = GetIdent(); parent=base_class->super; while(parent!=NULL) { sym = SymFindLocal(*name,parent); if(sym!=NULL) break; parent=parent->super; } if( sym!=NULL && sym->flags&SYM_PRIVATE ) { compileError("attempt to access private field '%s'",*name); NextToken(); return COMPILE_ERROR; } } /* check globals */ if( sym==NULL ) { *name = GetIdent(); sym = SymFind(*name); } return sym; }
Int32 parse(Pointer prog,Int32 size) { break_num=0; setlocal_num=0; return_num=0; in_class=FALSE; in_method=FALSE; cur_scope=SYM_PUBLIC; local_num=0; global_num=0; base_class=NULL; super_class=NULL; new_class=NULL; compile_error=FALSE; ScnInit(prog,size); if( Token==tERROR || Token==tEOF ) { compileError("EOF detected"); } else { compile_error=FALSE; SymInit(); Program(); SymFree(); } return compile_error; }
static void PrivateStatement(void) { SkipToken(tPRIVATE); cur_scope=SYM_PRIVATE; if(!in_class || in_method) { compileError("private only valid inside a class definition"); } }
static void ProtectedStatement(void) { SkipToken(tPROTECTED); cur_scope=SYM_PROTECTED; if(!in_class || in_method) { compileError("protected only valid inside a class definition"); } }
static void PublicStatement(void) { SkipToken(tPUBLIC); cur_scope=SYM_PUBLIC; if(!in_class || in_method) { compileError("public only valid inside a class definition"); } }
static void FunctionCall(SymPtr sym,SymPtr clas) { Int32 argc; /* push retval */ vm_genI(op_pushint,0); /* push args */ argc = 0; if( xstrcmp(sym->name,NEW)!=0 ) { argc = ActualParams(); } if( sym->nargs != -1 ) { if( sym->nargs != argc ) { compileError("wrong number of arguments in function call"); } } /* push class if necessary */ if( clas!=NULL ) { argc++; if( is_global_kind(clas) ) { vm_genI(op_getglobal,clas->num); } else if( is_local_kind(clas) ) { vm_genI(op_getlocal,clas->num); } } else if( in_class && sym->clas!=NULL ) { argc++; vm_genI(op_getlocal,-2); } /* push argc */ vm_genI(op_pushint,argc); /* call the function */ if( sym->kind==FUNCTION_KIND ) { vm_genI(op_jsr,sym->object.u.ival); } else if( sym->kind==CFUNCTION_KIND ) { vm_genI(op_call,sym->index); } }
static void LibraryStatement(void) { char *libname; SkipToken(tLIBRARY); if( Token==tSTRINGCONST ) { libname=GetString(); LibLoad(libname); /* ignored in console version */ NextToken(); } else compileError("expected library name"); }
ScriptErrorWidget::ScriptErrorWidget(QWidget *parent) : QDockWidget(parent), ui(new Ui::ScriptErrorWidget) { ui->setupUi(this); connect(HilecSingleton::hilec(), SIGNAL(compileError(ScriptCompileInfo)), SLOT(updateCompileError(ScriptCompileInfo))); mErrorIcons[ScriptCompileProblem::Error] = QIcon(":/ProjectEditor/exclamation.png"); mErrorIcons[ScriptCompileProblem::Warning] = QIcon(":/ProjectEditor/error.png"); mErrorIcons[ScriptCompileProblem::Info] = QIcon(":/ProjectEditor/information.png"); mModeEnabled[ScriptCompileProblem::Info] = false; mModeEnabled[ScriptCompileProblem::Warning] = true; mModeEnabled[ScriptCompileProblem::Error] = true; ui->enableErrors->setChecked(mModeEnabled[ScriptCompileProblem::Error]); ui->enableWarnings->setChecked(mModeEnabled[ScriptCompileProblem::Warning]); ui->enableInfos->setChecked(mModeEnabled[ScriptCompileProblem::Info]); }
bool DuckCompiler::compile(const QString &code, QByteArray *data) { QStringList lines = code.split(QRegExp("\\n")); currentLine = 0; int errorCount = 0; int processedCount = 0; QString prevInstruction; QString prevArgument; foreach (QString line, lines) { currentLine++; int defaultDelay = DEFAULT_DELAY; int repeat = 0; QString cleanLine = line.trimmed(); if (!cleanLine.isEmpty() && !cleanLine.startsWith("//")) { QStringList instructions = cleanLine.split(QRegExp("\\s")); const QString &instruction = instructions[0]; const QString & argument = instructions.length() == 2 ? instructions[1].trimmed() : ""; if (instruction == "REM") { continue; } bool ok = processInstruction(instruction, argument, data, &repeat, &defaultDelay); if (ok) { if (repeat > 0 && (prevInstruction.isEmpty() || prevInstruction == "REPEAT" || currentLine == 1)) { emit compileError(currentLine, 0, QString(tr("unable to repeat previous instruction"))); errorCount++; continue; } processedCount++; while (ok && repeat > 0) { repeat--; ok = processInstruction(prevInstruction, prevArgument, data); } prevInstruction = instruction; prevArgument = argument; } else { errorCount++; } } }
static int compileInner(EcCompiler *cp, int argc, char **argv) { Ejs *ejs; EjsModule *mp; MprList *nodes; EjsBlock *block; EcLocation loc; cchar *ext; char *msg; int next, i, j, nextModule, lflags, rc, paused; ejs = cp->ejs; if ((nodes = mprCreateList(-1, 0)) == 0) { return EJS_ERR; } cp->nodes = nodes; /* Warn about source files mentioned multiple times. TODO OPT. This is slow. */ for (i = 0; i < argc; i++) { for (j = 0; j < argc; j++) { if (i == j) { continue; } if (mprSamePath(argv[i], argv[j])) { compileError(cp, "Loading source %s multiple times. Ignoring extra copies.", argv[i]); return EJS_ERR; } } if (cp->outputFile && mprSamePath(cp->outputFile, argv[i])) { compileError(cp, "Output file is the same as input file: %s", argv[i]); return EJS_ERR; } } /* Compile source files and load any module files */ for (i = 0; i < argc && !cp->fatalError; i++) { ext = mprGetPathExt(argv[i]); if (scasecmp(ext, "mod") == 0 || scasecmp(ext, BIT_SHOBJ) == 0) { nextModule = mprGetListLength(ejs->modules); lflags = cp->strict ? EJS_LOADER_STRICT : 0; if ((rc = ejsLoadModule(cp->ejs, ejsCreateStringFromAsc(ejs, argv[i]), -1, -1, lflags)) < 0) { msg = sfmt("Error initializing module %s\n%s", argv[i], ejsGetErrorMsg(cp->ejs, 1)); memset(&loc, 0, sizeof(EcLocation)); loc.filename = sclone(argv[i]); if (rc == MPR_ERR_CANT_INITIALIZE) { ecError(cp, "Error", &loc, msg); } else { ecError(cp, "Error", &loc, msg); } cp->nodes = NULL; return EJS_ERR; } if (cp->merge) { /* If merging, we must emit the loaded module into the output. So add to the compiled modules list. */ for (next = nextModule; (mp = mprGetNextItem(ejs->modules, &next)) != 0; ) { if (mprLookupItem(cp->modules, mp) < 0 && mprAddItem(cp->modules, mp) < 0) { compileError(cp, "Can't add module %s", mp->name); } } } mprAddItem(nodes, 0); } else { mprAssert(!MPR->marking); paused = ejsBlockGC(ejs); mprAddItem(nodes, ecParseFile(cp, argv[i])); ejsUnblockGC(ejs, paused); } mprAssert(!MPR->marking); } mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); /* Allocate the eval frame stack. This is used for property lookups. We have one dummy block at the top always. */ block = ejsCreateBlock(ejs, 0); mprSetName(block, "Compiler"); ejsPushBlock(ejs, block); /* Process the internal representation and generate code */ paused = ejsBlockGC(ejs); if (!cp->parseOnly && cp->errorCount == 0) { ecResetParser(cp); if (ecAstProcess(cp) < 0) { ejsPopBlock(ejs); cp->nodes = NULL; ejsUnblockGC(ejs, paused); return EJS_ERR; } if (cp->errorCount == 0) { ecResetParser(cp); if (ecCodeGen(cp) < 0) { ejsPopBlock(ejs); cp->nodes = NULL; ejsUnblockGC(ejs, paused); return EJS_ERR; } } } ejsPopBlock(ejs); mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); /* Add compiled modules to the interpreter */ for (next = 0; ((mp = (EjsModule*) mprGetNextItem(cp->modules, &next)) != 0); ) { ejsAddModule(cp->ejs, mp); } cp->nodes = NULL; ejsUnblockGC(ejs, paused); if (!paused) { mprYield(0); } mprAssert(ejs->result == 0 || (MPR_GET_GEN(MPR_GET_MEM(ejs->result)) != MPR->heap->dead)); return (cp->errorCount > 0) ? EJS_ERR: 0; }
bool AssignmentThread::traditionalTaskPrepare() { compileState = NoValidSourceFile; QDir contestantDir = QDir(Settings::sourcePath() + contestantName); QList<Compiler*> compilerList = settings->getCompilerList(); for (int i = 0; i < compilerList.size(); i ++) { if (task->getCompilerConfiguration(compilerList[i]->getCompilerName()) == "disable") continue; QStringList filters = compilerList[i]->getSourceExtensions(); for (int j = 0; j < filters.size(); j ++) { filters[j] = task->getSourceFileName() + "." + filters[j]; } QStringList files = contestantDir.entryList(filters, QDir::Files); sourceFile = ""; for (int j = 0; j < files.size(); j ++) { qint64 fileSize = QFileInfo(Settings::sourcePath() + contestantName + QDir::separator() + files[j]).size(); if (fileSize <= settings->getFileSizeLimit() * 1024) { sourceFile = files[j]; break; } } if (! sourceFile.isEmpty()) { QDir(Settings::temporaryPath()).mkdir(contestantName); QFile::copy(Settings::sourcePath() + contestantName + QDir::separator() + sourceFile, Settings::temporaryPath() + contestantName + QDir::separator() + sourceFile); QStringList configurationNames = compilerList[i]->getConfigurationNames(); QStringList compilerArguments = compilerList[i]->getCompilerArguments(); QStringList interpreterArguments = compilerList[i]->getInterpreterArguments(); QString currentConfiguration = task->getCompilerConfiguration(compilerList[i]->getCompilerName()); for (int j = 0; j < configurationNames.size(); j ++) { if (configurationNames[j] == currentConfiguration) { timeLimitRatio = compilerList[i]->getTimeLimitRatio(); memoryLimitRatio = compilerList[i]->getMemoryLimitRatio(); disableMemoryLimitCheck = compilerList[i]->getDisableMemoryLimitCheck(); environment = compilerList[i]->getEnvironment(); QStringList values = environment.toStringList(); for (int k = 0; k < values.size(); k ++) { int tmp = values[k].indexOf("="); QString variable = values[k].mid(0, tmp); environment.insert(variable, environment.value(variable) + ";" + QProcessEnvironment::systemEnvironment().value(variable)); } if (compilerList[i]->getCompilerType() == Compiler::Typical) { #ifdef Q_OS_WIN32 executableFile = task->getSourceFileName() + ".exe"; #endif #ifdef Q_OS_LINUX executableFile = task->getSourceFileName(); #endif interpreterFlag = false; } else { executableFile = compilerList[i]->getInterpreterLocation(); arguments = interpreterArguments[j]; arguments.replace("%s.*", sourceFile); arguments.replace("%s", task->getSourceFileName()); interpreterFlag = true; } if (compilerList[i]->getCompilerType() != Compiler::InterpretiveWithoutByteCode) { QString arguments = compilerArguments[j]; arguments.replace("%s.*", sourceFile); arguments.replace("%s", task->getSourceFileName()); QProcess *compiler = new QProcess(this); compiler->setProcessChannelMode(QProcess::MergedChannels); compiler->setProcessEnvironment(environment); compiler->setWorkingDirectory(Settings::temporaryPath() + contestantName); compiler->start(QString("\"") + compilerList[i]->getCompilerLocation() + "\" " + arguments); if (! compiler->waitForStarted(-1)) { compileState = InvalidCompiler; delete compiler; break; } QElapsedTimer timer; timer.start(); bool flag = false; while (timer.elapsed() < settings->getCompileTimeLimit()) { if (compiler->state() != QProcess::Running) { flag = true; break; } QCoreApplication::processEvents(); if (stopJudging) { compiler->kill(); delete compiler; return false; } msleep(10); } if (! flag) { compiler->kill(); compileState = CompileTimeLimitExceeded; } else if (compiler->exitCode() != 0) { compileState = CompileError; compileMessage = QString::fromLocal8Bit(compiler->readAllStandardOutput().data()); } else { if (compilerList[i]->getCompilerType() == Compiler::Typical) { if (! QDir(Settings::temporaryPath() + contestantName).exists(executableFile)) { compileState = InvalidCompiler; } else { compileState = CompileSuccessfully; } } else { QStringList filters = compilerList[i]->getBytecodeExtensions(); for (int k = 0; k < filters.size(); k ++) { filters[k] = QString("*.") + filters[k]; } if (QDir(Settings::temporaryPath() + contestantName) .entryList(filters, QDir::Files).size() == 0) { compileState = InvalidCompiler; } else { compileState = CompileSuccessfully; } } } delete compiler; } if (compilerList[i]->getCompilerType() == Compiler::InterpretiveWithoutByteCode) compileState = CompileSuccessfully; break; } } break; } } if (compileState != CompileSuccessfully) { emit compileError(task->getTotalTimeLimit(), (int)compileState); return false; } return true; }
static void ClassDefinition(void) { char *name; Int32 label,l1; Int32 field_num=0; SymPtr clas,clas_init; SkipToken(tCLASS); MatchToken(tCONST); name = GetIdent(); clas = SymAdd(name); clas->kind = CLASS_KIND; NextToken(); in_class=TRUE; base_class=clas; cur_scope=SYM_PUBLIC; /* clas->super=NULL; */ /* super_class=NULL; */ clas->super=SymFind("Object"); super_class=clas->super; if( Token==tLSS ) { SkipToken(tLSS); MatchToken(tCONST); name = GetIdent(); clas->super = SymFind(name); if( clas->super==NULL ) { compileError("super class not found"); return; } super_class = clas->super; field_num = clas->super->nlocs; NextToken(); } SymEnterScope(); /* default class constructor prologue */ l1 = vm_genI(op_link,0); clas_init = SymAdd(NEW); clas_init->kind = FUNCTION_KIND; clas_init->object.u.ival = l1; clas_init->flags |= SYM_PUBLIC; /* class fields and functions */ while( TokenIn(class_statements) ) { if( Token==tPUBLIC ) { PublicStatement(); } else if( Token==tPROTECTED ) { ProtectedStatement(); } else if( Token==tPRIVATE ) { PrivateStatement(); } else if( Token==tDEF ) { label = vm_genI(op_jmp,0); MethodDefinition(); vm_patch(label,vm_addr()); } else { local_num = field_num++; AssignmentStatement(); } if( Token==tSEMI ) SkipToken(tSEMI); } clas->nlocs = field_num; /* default class constructor epilogue */ vm_gen0(op_nop); vm_genI(op_rts,2); SymExitScope(clas); /* end of class */ in_class=FALSE; base_class=NULL; super_class=NULL; SkipToken(tEND); if( Token==tSEMI ) SkipToken(tSEMI); }
static Int32 Rhs(void) { char *name=NULL; SymPtr sym,clas=NULL; sym = LookupIdent(&name); if( sym == COMPILE_ERROR ) { return INT_TYPE; } NextToken(); if( sym==NULL ) { compileError("invalid identifier '%s'",name); return INT_TYPE; } /* check for field access */ if( Token==tPERIOD ) { if( in_class && !in_method ) { compileError("cannot initialize fields with objects"); return INT_TYPE; } clas = sym; sym = FieldReference(clas); if( sym==NULL ) { return INT_TYPE; } if( xstrcmp(sym->name,NEW)==0 ) { new_class = clas; vm_genI(op_newclass,new_class->nlocs); return CLASS_TYPE; } } switch(sym->kind) { case NIL_KIND: compileError("invalid type"); break; case GLOBAL_KIND: vm_genI(op_getglobal,sym->num); break; case LOCAL_KIND: vm_genI(op_getlocal,sym->num); break; case CONSTANT_KIND: switch(sym->object.type) { case INT_TYPE: vm_genI(op_pushint,sym->object.u.ival); break; case REAL_TYPE: vm_genR(op_pushreal,sym->object.u.rval); break; case STRING_TYPE: vm_genS(op_pushstring,sym->object.u.pval); break; default: /* TODO: error */ break; } break; case FUNCTION_KIND: case CFUNCTION_KIND: FunctionCall(sym,clas); break; case CLASS_KIND: compileError("invalid type"); break; case FIELD_KIND: CheckClassMember(sym); vm_genI(op_getfield,sym->num); break; } /* check for array access */ if( Token==tLBRACK ) { /* allow multi-dimensional arrays */ while( Token==tLBRACK ) { /* valid array is checked at runtime */ SkipToken(tLBRACK); Expr(); SkipToken(tRBRACK); vm_gen0(op_getarray); } } return sym->object.type; }
static SymPtr Lhs(void) { char *name=NULL; SymPtr sym,clas=NULL; sym = LookupIdent(&name); if( sym==COMPILE_ERROR ) { return NULL; } NextToken(); /* if a field has the same name as a global, it will override */ if( in_class && SymGetScope()==2 && sym!=NULL ) { if( sym->kind==GLOBAL_KIND ) { sym=NULL; } } if( sym==NULL ) { sym = SymAdd(name); if( Token==tCONST ) { sym->flags |= SYM_CONSTANT; } if( SymGetScope()==1 ) { sym->kind = GLOBAL_KIND; sym->num = global_num++; } else { /* MCC */ if(in_class && !in_method) { sym->kind = FIELD_KIND; sym->flags |= cur_scope; sym->clas = base_class; } else { sym->kind = LOCAL_KIND; sym->flags = 0; sym->clas = NULL; } sym->num = local_num++; } return sym; } /* check for field access */ if( Token==tPERIOD ) { clas = sym; sym = FieldReference(clas); if( sym==NULL ) { return NULL; } } /* check for function call */ if( is_func_kind(sym) ) { FunctionCall(sym,clas); vm_gen0(op_pop); return NULL; } /* check for array access */ if( Token==tLBRACK ) { switch(sym->kind) { case GLOBAL_KIND: vm_genI(op_getglobal,sym->num); break; case LOCAL_KIND: vm_genI(op_getlocal,sym->num); break; case CONSTANT_KIND: switch(sym->object.type) { case INT_TYPE: vm_genI(op_pushint,sym->object.u.ival); break; case REAL_TYPE: vm_genR(op_pushreal,sym->object.u.rval); break; case STRING_TYPE: vm_genS(op_pushstring,sym->object.u.pval); break; default: /* TODO: error */ break; } break; case FIELD_KIND: CheckClassMember(sym); vm_genI(op_getfield,sym->num); break; default: compileError("invalid assignment"); break; } if( Token==tLBRACK ) /* array */ { SkipToken(tLBRACK); Expr(); SkipToken(tRBRACK); while( Token==tLBRACK ) { /* handle multi-dimension arrays */ vm_gen0(op_getarray); SkipToken(tLBRACK); Expr(); SkipToken(tRBRACK); } SkipToken(tEQUALS); Expr(); vm_gen0(op_setarray); return NULL; } } return sym; }
static void AssignmentStatement(void) { Int32 type,count; SymPtr sym,clas_init=NULL; SymPtr parents[16]; sym = Lhs(); if( sym==NULL ) { return; } CheckClassMember(sym); SkipToken(tEQUALS); if(sym->flags&SYM_DEFINED) { compileError("cannot reassign constant"); return; } else if(sym->flags&SYM_CONSTANT) { sym->flags |= SYM_DEFINED; } /* CheckClassMember(sym); */ new_class=NULL; type=Expr(); sym->object.type = type; switch(sym->kind) { case LOCAL_KIND: vm_genI(op_setlocal,sym->num); break; case GLOBAL_KIND: vm_genI(op_setglobal,sym->num); break; case FIELD_KIND: vm_genI(op_setfield,sym->num); break; default: compileError("invalid assignment"); break; } if( type==CLASS_TYPE && new_class != NULL ) { sym->clas = new_class; sym->super = new_class->super; sym->locals = new_class->locals; /* First build a list of all super classes */ count=0; clas_init=sym; while( clas_init!=NULL ) { parents[count++] = clas_init; clas_init = clas_init->super; } /* Now call all constructors in reverse order */ count--; while( count>=0 ) { clas_init = SymFindLocal(NEW,parents[count]); FunctionCall(clas_init,sym); vm_gen0(op_pop); count--; } /* call user defined constructor */ clas_init=SymFindLocal("init",sym); if( clas_init!=NULL ) { if( (Token==tLPAREN && clas_init->nargs!=0) || (Token!=tLPAREN && clas_init->nargs==0) ) { FunctionCall(clas_init,sym); vm_gen0(op_pop); } } } }