asebatest.cpp
Go to the documentation of this file.
00001 // Aseba
00002 #include "../compiler/compiler.h"
00003 #include "../vm/vm.h"
00004 #include "../vm/natives.h"
00005 #include "../common/consts.h"
00006 #include "../utils/utils.h"
00007 #include "../utils/FormatableString.h"
00008 using namespace Aseba;
00009 
00010 // C++
00011 #include <string>
00012 #include <iostream>
00013 #include <locale>
00014 #include <fstream>
00015 #include <sstream>
00016 #include <valarray>
00017 
00018 // C
00019 #include <getopt.h>             // getopt_long()
00020 #include <stdlib.h>             // exit()
00021 
00022 // helper function
00023 std::wstring read_source(const std::string& filename);
00024 void dump_source(const std::wstring& source);
00025 
00026 static const char short_options [] = "fsdm:";
00027 static const struct option long_options[] = { 
00028         { "fail",       no_argument,            NULL,           'f'},
00029         { "source",     no_argument,            NULL,           's'},
00030         { "dump",       no_argument,            NULL,           'd'},
00031         { "memdump",    no_argument,            NULL,           'u'},
00032         { "memcmp",     required_argument,      NULL,           'm'},
00033         { 0, 0, 0, 0 } 
00034 };
00035 
00036 static void usage (int argc, char** argv)
00037 {
00038         std::cerr       << "Usage: " << argv[0] << " [options] source" << std::endl << std::endl
00039                         << "Options:" << std::endl
00040                         << "    -f | --fail         Return EXIT_SUCCESS if compilation fail" << std::endl
00041                         << "    -s | --source       Dump the source code" << std::endl
00042                         << "    -d | --dump         Dump the compilation result (tokens, tree, bytecode)" << std::endl
00043                         << "    -u | --memdump      Dump the memory content at the end of the execution" << std::endl
00044                         << "    -m | --memcmp file  Compare result of the VM execution with file" << std::endl;
00045 }
00046 
00047 static bool executionError(false);
00048 
00049 extern "C" void AsebaSendMessage(AsebaVMState *vm, uint16 type, const void *data, uint16 size)
00050 {
00051         switch (type)
00052         {
00053                 case ASEBA_MESSAGE_DIVISION_BY_ZERO:
00054                 std::cerr << "Division by zero" << std::endl;
00055                 executionError = true;
00056                 break;
00057                 
00058                 case ASEBA_MESSAGE_ARRAY_ACCESS_OUT_OF_BOUNDS:
00059                 std::cerr << "Array access out of bounds" << std::endl;
00060                 executionError = true;
00061                 break;
00062                 
00063                 default:
00064                 std::cerr << "AsebaSendMessage of type " << type << ", size " << size << std::endl;
00065                 break;
00066         }
00067 }
00068 
00069 #ifdef __BIG_ENDIAN__
00070 extern "C" void AsebaSendMessageWords(AsebaVMState *vm, uint16 type, const uint16* data, uint16 count)
00071 {
00072         AsebaSendMessage(vm, type, data, count*2);
00073 }
00074 #endif
00075 
00076 extern "C" void AsebaSendVariables(AsebaVMState *vm, uint16 start, uint16 length)
00077 {
00078         std::cerr << "AsebaSendVariables at pos " << start << ", length " << length << std::endl;
00079 }
00080 
00081 extern "C" void AsebaSendDescription(AsebaVMState *vm)
00082 {
00083         std::cerr << "AsebaSendDescription" << std::endl;
00084 }
00085 
00086 extern "C" void AsebaPutVmToSleep(AsebaVMState *vm)
00087 {
00088         std::cerr << "AsebaPutVmToSleep" << std::endl;
00089 }
00090 
00091 static AsebaNativeFunctionPointer nativeFunctions[] =
00092 {
00093         ASEBA_NATIVES_STD_FUNCTIONS,
00094 };
00095 
00096 static const AsebaNativeFunctionDescription* nativeFunctionsDescriptions[] =
00097 {
00098         ASEBA_NATIVES_STD_DESCRIPTIONS,
00099         0
00100 };
00101 
00102 extern "C" const AsebaNativeFunctionDescription * const * AsebaGetNativeFunctionsDescriptions(AsebaVMState *vm)
00103 {
00104         return nativeFunctionsDescriptions;
00105 }
00106 
00107 extern "C" void AsebaNativeFunction(AsebaVMState *vm, uint16 id)
00108 {
00109         nativeFunctions[id](vm);
00110 }
00111 
00112 extern "C" void AsebaWriteBytecode(AsebaVMState *vm)
00113 {
00114         std::cerr << "AsebaWriteBytecode" << std::endl;
00115 }
00116 
00117 extern "C" void AsebaResetIntoBootloader(AsebaVMState *vm)
00118 {
00119         std::cerr << "AsebaResetIntoBootloader" << std::endl;
00120 }
00121 
00122 extern "C" void AsebaAssert(AsebaVMState *vm, AsebaAssertReason reason)
00123 {
00124         std::cerr << "\nFatal error, internal VM exception: ";
00125         switch (reason)
00126         {
00127                 case ASEBA_ASSERT_UNKNOWN: std::cerr << "undefined"; break;
00128                 case ASEBA_ASSERT_UNKNOWN_UNARY_OPERATOR: std::cerr << "unknown unary operator"; break;
00129                 case ASEBA_ASSERT_UNKNOWN_BINARY_OPERATOR: std::cerr << "unknown binary operator"; break;
00130                 case ASEBA_ASSERT_UNKNOWN_BYTECODE: std::cerr << "unknown bytecode"; break;
00131                 case ASEBA_ASSERT_STACK_OVERFLOW: std::cerr << "stack overflow"; break;
00132                 case ASEBA_ASSERT_STACK_UNDERFLOW: std::cerr << "stack underflow"; break;
00133                 case ASEBA_ASSERT_OUT_OF_VARIABLES_BOUNDS: std::cerr << "out of variables bounds"; break;
00134                 case ASEBA_ASSERT_OUT_OF_BYTECODE_BOUNDS: std::cerr << "out of bytecode bounds"; break;
00135                 case ASEBA_ASSERT_STEP_OUT_OF_RUN: std::cerr << "step out of run"; break;
00136                 case ASEBA_ASSERT_BREAKPOINT_OUT_OF_BYTECODE_BOUNDS: std::cerr << "breakpoint out of bytecode bounds"; break;
00137                 case ASEBA_ASSERT_EMIT_BUFFER_TOO_LONG: std::cerr << "tried to emit a buffer too long"; break;
00138                 default: std::cerr << "unknown exception"; break;
00139         }
00140         std::cerr << ".\npc = " << vm->pc << ", sp = " << vm->sp;
00141         std::cerr << "\nResetting VM" << std::endl;
00142         executionError = true;
00143         AsebaVMInit(vm);
00144 }
00145 
00146 struct AsebaNode
00147 {
00148         AsebaVMState vm;
00149         std::valarray<unsigned short> bytecode;
00150         std::valarray<signed short> stack;
00151         TargetDescription d;
00152         
00153         struct Variables
00154         {
00155                 sint16 user[256];
00156         } variables;
00157 
00158         AsebaNode()
00159         {
00160                 // create VM
00161                 vm.nodeId = 0;
00162                 bytecode.resize(512);
00163                 vm.bytecode = &bytecode[0];
00164                 vm.bytecodeSize = bytecode.size();
00165                 
00166                 stack.resize(64);
00167                 vm.stack = &stack[0];
00168                 vm.stackSize = stack.size();
00169                 
00170                 vm.variables = reinterpret_cast<sint16 *>(&variables);
00171                 vm.variablesSize = sizeof(variables) / sizeof(sint16);
00172                 
00173                 AsebaVMInit(&vm);
00174                 
00175                 // fill description accordingly
00176                 d.name = L"testvm";
00177                 d.protocolVersion = ASEBA_PROTOCOL_VERSION;
00178                 
00179                 d.bytecodeSize = vm.bytecodeSize;
00180                 d.variablesSize = vm.variablesSize;
00181                 d.stackSize = vm.stackSize;
00182                 
00183                 /*d.namedVariables.push_back(TargetDescription::NamedVariable("id", 1));
00184                 d.namedVariables.push_back(TargetDescription::NamedVariable("source", 1));
00185                 d.namedVariables.push_back(TargetDescription::NamedVariable("args", 32));*/
00186                 
00187                 const AsebaNativeFunctionDescription** nativeDescs(nativeFunctionsDescriptions);
00188                 while (*nativeDescs)
00189                 {
00190                         const AsebaNativeFunctionDescription* nativeDesc(*nativeDescs);
00191                         std::string name(nativeDesc->name);
00192                         std::string doc(nativeDesc->doc);
00193                         
00194                         TargetDescription::NativeFunction native(
00195                                 std::wstring(name.begin(), name.end()),
00196                                 std::wstring(doc.begin(), doc.end())
00197                         );
00198                         
00199                         const AsebaNativeFunctionArgumentDescription* params(nativeDesc->arguments);
00200                         while (params->size)
00201                         {
00202                                 AsebaNativeFunctionArgumentDescription param(*params);
00203                                 name = param.name;
00204                                 int size = param.size;
00205                                 native.parameters.push_back(
00206                                         TargetDescription::NativeFunctionParameter(std::wstring(name.begin(), name.end()), size)
00207                                 );
00208                                 ++params;
00209                         }
00210                         
00211                         d.nativeFunctions.push_back(native);
00212                         
00213                         ++nativeDescs;
00214                 }
00215         }
00216         
00217         const TargetDescription* getTargetDescription() const
00218         {
00219                 return &d;
00220         }
00221 
00222         bool loadBytecode(const BytecodeVector& bytecode)
00223         {
00224                 size_t i = 0;
00225                 for (BytecodeVector::const_iterator it(bytecode.begin()); it != bytecode.end(); ++it)
00226                 {
00227                         if (i == vm.bytecodeSize)
00228                                 return false;
00229                         const BytecodeElement& be(*it);
00230                         vm.bytecode[i++] = be.bytecode;
00231                 }
00232                 return true;
00233         }
00234         
00235         void run()
00236         {
00237                 // run VM
00238                 AsebaVMSetupEvent(&vm, ASEBA_EVENT_INIT);
00239                 AsebaVMRun(&vm, 1000);
00240         }
00241 };
00242 
00243 void checkForError(const std::string& module, bool shouldFail, bool wasError, const std::wstring& errorMessage = L"")
00244 {
00245         if (wasError)
00246         {
00247                 // errors
00248                 std::cerr << "An error in " << module << " occured";
00249                 if (!errorMessage.empty())
00250                         std::wcerr << ':' << std::endl << errorMessage;
00251                 std::cerr << std::endl;
00252                 if (shouldFail)
00253                 {
00254                         // this was expected
00255                         std::cerr << "Failure was expected" << std::endl;
00256                         exit(EXIT_SUCCESS);
00257                 }
00258                 else
00259                 {
00260                         // oops
00261                         exit(EXIT_FAILURE);
00262                 }
00263         }
00264         else
00265         {
00266                 // no errors
00267                 std::cerr << module << " was successful" << std::endl;
00268         }
00269 }
00270 
00271 int main(int argc, char** argv)
00272 {
00273         bool should_fail = false;
00274         bool source = false;
00275         bool dump = false;
00276         bool memDump = false;
00277         bool memCmp = false;
00278         std::string memCmpFileName;
00279         
00280         std::locale::global(std::locale(""));
00281         
00282         // parse the arguments
00283         for(;;)
00284         {
00285                 int index;
00286                 int c;
00287 
00288                 c = getopt_long(argc, argv, short_options, long_options, &index);
00289 
00290                 if (c==-1)
00291                         break;
00292 
00293                 switch(c)
00294                 {
00295                         case 0: // getopt_long() flag
00296                                 break;
00297                         case 'f':
00298                                 should_fail = true;
00299                                 break;
00300                         case 's':
00301                                 source = true;
00302                                 break;
00303                         case 'd':
00304                                 dump = true;
00305                                 break;
00306                         case 'u':
00307                                 memDump = true;
00308                                 break;
00309                         case 'm':
00310                                 memCmp = true;
00311                                 memCmpFileName = optarg;
00312                                 break;
00313                         default:
00314                                 usage(argc, argv);
00315                                 exit(EXIT_FAILURE);
00316                 }
00317         }
00318 
00319         std::string filename;
00320         
00321         // check for the source file
00322         if (optind == (argc-1))
00323         {
00324                 filename.assign(argv[optind]);
00325         }
00326         else
00327         {
00328                 usage(argc, argv);
00329                 exit(EXIT_FAILURE);
00330         }
00331         
00332         // read source
00333         const std::wstring wSource = read_source(filename);
00334         
00335         // dump source
00336         if (source)
00337                 dump_source(wSource);
00338         
00339         // parse source
00340         std::wistringstream ifs(wSource);
00341 
00342         Compiler compiler;
00343 
00344         // fake target description
00345         AsebaNode node;
00346         CommonDefinitions definitions;
00347         definitions.events.push_back(NamedValue(L"event1", 0));
00348         definitions.events.push_back(NamedValue(L"event2", 3));
00349         definitions.constants.push_back(NamedValue(L"FOO", 2));
00350 
00351         BytecodeVector bytecode;
00352         unsigned int varCount;
00353         Error outError;
00354 
00355         // compile
00356         compiler.setTargetDescription(node.getTargetDescription());
00357         compiler.setCommonDefinitions(&definitions);
00358         if (dump)
00359                 compiler.compile(ifs, bytecode, varCount, outError, &(std::wcout));
00360         else
00361                 compiler.compile(ifs, bytecode, varCount, outError, NULL);
00362 
00363         //ifs.close();
00364         
00365         checkForError("Compilation", should_fail, (outError.message != L"not defined"), outError.toWString());
00366         
00367         // run
00368         if (!node.loadBytecode(bytecode))
00369         {
00370                 std::cerr << "Load bytecode failure" << std::endl;
00371                 return EXIT_FAILURE;
00372         }
00373         node.run();
00374         
00375         checkForError("Execution", should_fail, executionError);
00376 
00377         if (memDump)
00378         {
00379                 std::wcout << L"Memory dump:" << std::endl;
00380                 for (int i = 0; i < node.vm.variablesSize; i++)
00381                 {
00382                         std::wcout << node.vm.variables[i] << std::endl;
00383                 }
00384         }
00385         
00386         if (memCmp)
00387         {
00388                 std::ifstream ifs;
00389                 ifs.open(memCmpFileName.data(), std::ifstream::in);
00390                 if (!ifs.is_open())
00391                 {
00392                         std::cerr << "Error opening mem dump file " << memCmpFileName << std::endl;
00393                         exit(EXIT_FAILURE);
00394                 }
00395                 size_t i = 0;
00396                 while (!ifs.eof())
00397                 {
00398                         int v;
00399                         ifs >> v;
00400                         if (ifs.eof())
00401                                 break;
00402                         if (i >= node.vm.variablesSize)
00403                                 break;
00404                         if (node.vm.variables[i] != v)
00405                         {
00406                                 std::cerr << "VM variable value at pos " << i << " after execution differs from dump; expected: " << v << ", found: " << node.vm.variables[i] << std::endl;
00407                                 if (should_fail)
00408                                 {
00409                                         std::cerr << "Failure was expected" << std::endl;
00410                                         exit(EXIT_SUCCESS);
00411                                 }
00412                                 else
00413                                         exit(EXIT_FAILURE);
00414                         }
00415                         ++i;
00416                 }
00417                 ifs.close();
00418         }
00419         
00420         
00421         if (should_fail)
00422         {
00423                 std::cerr << "All tests passed successfully, but failure was expected" << std::endl;
00424                 exit(EXIT_FAILURE);
00425         }
00426         
00427         return EXIT_SUCCESS;
00428 }
00429 
00430 // read source code to a string
00431 std::wstring read_source(const std::string& filename)
00432 {
00433         std::ifstream ifs;
00434         ifs.open( filename.c_str(),std::ifstream::binary);
00435         if (!ifs.is_open())
00436         {
00437                 std::cerr << "Error opening source file " << filename << std::endl;
00438                 exit(EXIT_FAILURE);
00439         }
00440         
00441         ifs.seekg (0, std::ios::end);
00442         std::streampos length = ifs.tellg();
00443         ifs.seekg (0, std::ios::beg);
00444         
00445         std::string utf8Source;
00446         utf8Source.resize(length);
00447         ifs.read(&utf8Source[0], length);
00448         ifs.close();
00449         
00450         /*for (size_t i = 0; i < utf8Source.length(); ++i)
00451                 std::cerr << "source char " << i << " is 0x" << std::hex << (unsigned)(unsigned char)utf8Source[i] << " (" << char(utf8Source[i]) << ")" << std::endl;
00452         */
00453         const std::wstring s = UTF8ToWString(utf8Source);
00454         
00455         /*std::cerr << "len utf8 " << utf8Source.length() << " len final " << s.length() << std::endl;
00456         for (size_t i = 0; i < s.length(); ++i)
00457                 std::wcerr << "dest char " << i << " is 0x" << std::hex << (unsigned)s[i] << " (" << s[i] << ")"<< std::endl;
00458         */
00459         return s;
00460 }
00461 
00462 // dump program source
00463 void dump_source(const std::wstring& source)
00464 {
00465         std::wistringstream is(source);
00466         wchar_t c;
00467         std::cout << "Program:" << std::endl;
00468         int line = 1;
00469         bool header = true;
00470         while (is)
00471         {
00472                 if (header)
00473                 {
00474                         std::cout << line << "  ";
00475                         header = false;
00476                 }
00477                 c = is.get();
00478                 std::wcout << c;
00479                 if (c == '\n')
00480                 {
00481                         header = true;
00482                         line++;
00483                 }
00484         }
00485         std::cout << std::endl;
00486 }
00487 


aseba
Author(s): Stéphane Magnenat
autogenerated on Thu Jan 2 2014 11:17:16