ecere; ide; compiler: Fixed setting safety null character after (v)snprintf
[sdk] / compiler / ecc / ecc.ec
1 #ifdef ECERE_STATIC
2 import static "ecere"
3 import static "ec"
4 #else
5 import "ecere"
6 import "ec"
7 #endif
8
9 #include <stdarg.h>
10
11 static Context globalContext { };
12 static Module privateModule;
13 static ModuleImport mainModule;
14 static OldList _excludedSymbols { offset = (uint)&((Symbol)0).left }; 
15 static OldList defines, imports;
16 static NameSpace globalData
17 {
18    classes.CompareKey = (void *)BinaryTree::CompareString;
19    defines.CompareKey = (void *)BinaryTree::CompareString;
20    functions.CompareKey = (void *)BinaryTree::CompareString;
21    nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
22 };
23 static OldList _precompDefines;
24
25 static void OutputImports(char * fileName)
26 {
27    File f = FileOpen(fileName, write);
28    if(f)
29    {
30       if(imports.first)
31       {
32          ModuleImport module;
33          f.Printf("[Imported Modules]\n");
34          for(module = imports.first; module; module = module.next)
35          {
36             ClassImport _class;
37             FunctionImport function;
38
39             if(module.name)
40                f.Printf("   %s\n", module.name);
41             else
42                f.Printf("   [This]\n");
43             if(module.importType == staticImport)
44                f.Printf("      [Static]\n");
45             else if(module.importType == remoteImport)
46                f.Printf("      [Remote]\n");
47
48             if(module.importAccess == privateAccess)
49                f.Printf("      [Private]\n");
50             else
51                f.Printf("      [Public]\n");
52
53             if(module.classes.first)
54             {
55                f.Printf("      [Imported Classes]\n");
56                for(_class = module.classes.first; _class; _class = _class.next)
57                {
58                   f.Printf("         %s\n", _class.name);
59                   if(_class.itself)
60                   {
61                      f.Printf("            [Instantiated]\n");
62                   }
63                   if(_class.isRemote)
64                   {
65                      f.Printf("            [Remote]\n");
66                   }
67
68                   if(_class.methods.first)
69                   {
70                      MethodImport method;
71                      f.Printf("            [Imported Methods]\n");
72                      for(method = _class.methods.first; method; method = method.next)
73                      {
74                         f.Printf("               %s\n", method.name);
75                         if(method.isVirtual)
76                            f.Printf("                  [Virtual]\n");
77
78                      }
79                      f.Printf("               .\n");
80                   }
81
82                   if(_class.properties.first)
83                   {
84                      PropertyImport prop;
85                      f.Printf("            [Imported Properties]\n");
86                      for(prop = _class.properties.first; prop; prop = prop.next)
87                      {
88                         f.Printf("               %s\n", prop.name);
89                         if(prop.isVirtual)
90                            f.Printf("                  [Virtual]\n");
91                         if(prop.hasSet)
92                            f.Printf("                  [Set]\n");
93                         if(prop.hasGet)
94                            f.Printf("                  [Get]\n");
95                      }
96                      f.Printf("               .\n");
97                   }
98                }
99                f.Printf("        .\n");
100             }
101             if(module.functions.first)
102             {
103                f.Printf("      [Imported Functions]\n");
104                for(function = module.functions.first; function; function = function.next)
105                {
106                   f.Printf("         %s\n", function.name);
107                }
108                f.Printf("        .\n");
109             }
110          }
111          f.Printf("   .\n");
112       }
113    }
114    delete f;
115 }
116
117 class CompilerApp : Application
118 {
119    void Main()
120    {
121       char * cppCommand = null;
122       char * cppOptions = null;
123       int cppOptionsLen = 0;
124       /*char ** argv = null;
125       int argc = 0;*/
126       int c;
127       bool valid = true;
128       char defaultOutputFile[MAX_LOCATION];
129
130       Platform targetPlatform = GetRuntimePlatform();
131
132       SetSymbolsDir("");
133
134       /*for(c = 0; c<this.argc; c++)
135       {
136          char * arg = this.argv[c];
137          int argLen = strlen(arg);
138
139          argv = renew argv char *[argc + 1];
140          argv[argc] = new char[argLen+1];
141          strcpy(argv[argc], arg);
142
143          while(argv[argc][argLen-1] == '\\' && c < this.argc-1)
144          {
145             int len;
146
147             c++;
148             arg = this.argv[c];
149             len = strlen(arg);
150             argv[argc] = renew argv[argc] char[argLen + len + 1];
151
152             argv[argc][argLen-1] = ' ';
153             strcpy(argv[argc] + argLen, arg);
154             argLen += len;
155          }
156          argc++;
157       }*/
158
159       for(c = 1; c<argc; c++)
160       {
161          char * arg = argv[c];
162          if(arg[0] == '-')
163          {
164             if(!strcmp(arg + 1, "m32"))
165             {
166                int argLen = strlen(arg);
167                int newLen = cppOptionsLen + 1 + argLen;
168                cppOptions = renew cppOptions char[newLen + 1];
169                cppOptions[cppOptionsLen] = ' ';
170                strcpy(cppOptions + cppOptionsLen + 1, arg); 
171                cppOptionsLen = newLen;
172             }
173             else if(arg[1] == 'D')
174             {
175                int argLen = strlen(arg);
176                int newLen = cppOptionsLen + 1 + argLen;
177                cppOptions = renew cppOptions char[newLen + 1];
178                cppOptions[cppOptionsLen] = ' ';
179                strcpy(cppOptions + cppOptionsLen + 1, arg); 
180                cppOptionsLen = newLen;
181                if(!strcmp(arg, "-DBUILDING_ECERE_COM"))
182                   SetBuildingEcereCom(true);
183                else if(!strcmp(arg, "-DECERE_COM_MODULE"))
184                   SetBuildingEcereComModule(true);
185             }
186             else if(arg[1] == 'I')
187             {
188                int argLen = strlen(arg);
189                int newLen = cppOptionsLen + argLen + 3;
190                cppOptions = renew cppOptions char[newLen + 1];
191                cppOptions[cppOptionsLen] = ' ';
192                cppOptions[cppOptionsLen+1] = '-';
193                cppOptions[cppOptionsLen+2] = 'I';
194                cppOptions[cppOptionsLen+3] = '"';
195                strcpy(cppOptions + cppOptionsLen + 4, arg+2); 
196                cppOptions[newLen-1] = '\"';
197                cppOptions[newLen] = '\0';
198                cppOptionsLen = newLen;
199             }
200             else if(!strcmp(arg+1, "t"))
201             {
202                if(++c < argc)
203                   targetPlatform = argv[c];
204                else
205                   valid = false;
206             }
207             else if(!strcmp(arg+1, "cpp"))
208             {
209                if(++c < argc)
210                   cppCommand = CopyString(argv[c]);
211                else
212                   valid = false;
213             }
214             else if(!strcmp(arg+1, "o"))
215             {
216                if(!GetOutputFile() && c + 1 < argc)
217                {
218                   SetOutputFile(argv[c+1]);
219                   c++;
220                }
221                else
222                   valid = false;
223             }
224             else if(!strcmp(arg+1, "c"))
225             {
226                if(!GetSourceFile() && c + 1 < argc)
227                {
228                   SetSourceFile(argv[c+1]);
229                   c++;
230                }
231                else
232                   valid = false;
233             }
234             else if(!strcmp(arg+1, "isystem") || !strcmp(arg+1, "isysroot"))
235             {
236                if(c + 1 < argc)
237                {
238                   int argLen = strlen(arg);
239                   int arg1Len = strlen(argv[c+1]);
240                   int newLen = cppOptionsLen + argLen + arg1Len + 4;
241                   cppOptions = renew cppOptions char[newLen + 1];
242                   cppOptions[cppOptionsLen] = ' ';
243                   strcpy(cppOptions + cppOptionsLen + 1, arg); 
244                   cppOptions[cppOptionsLen+argLen+1] = ' ';
245                   cppOptions[cppOptionsLen+argLen+2] = '"';
246                   arg = argv[++c];
247                   strcpy(cppOptions + cppOptionsLen + argLen + 3, arg); 
248                   cppOptions[newLen-1] = '\"';
249                   cppOptions[newLen] = '\0';
250                   cppOptionsLen = newLen;
251                }
252                else
253                   valid = false;
254             }
255             else if(!strcmp(arg+1, "symbols"))
256             {
257                if(c + 1 < argc)
258                {
259                   SetSymbolsDir(argv[c+1]);
260                   c++;
261                }
262                else
263                   valid = false;
264             }
265             else if(!strcmp(arg+1, "memguard"))
266             {
267                SetMemoryGuard(true);
268             }
269             else if(!strcmp(arg+1, "defaultns"))
270             {
271                if(c + 1 < argc)
272                {
273                   SetDefaultNameSpace(argv[c+1]);
274                   //defaultNameSpaceLen = strlen(defaultNameSpace);
275                   c++;
276                }
277                else
278                   valid = false;
279             }
280             else if(!strcmp(arg+1, "strictns"))
281             {
282                SetStrictNameSpaces(true);
283             }
284             else if(!strcmp(arg+1, "nolinenumbers"))
285             {
286                SetOutputLineNumbers(false);
287             }
288          }
289          else
290             valid = false;
291       }
292       if(valid)
293       {
294          if(!cppCommand)
295             cppCommand = CopyString("gcc");
296          if(!GetSourceFile())
297             valid = false;
298          else if(!GetOutputFile())
299          {
300             strcpy(defaultOutputFile, "");
301             PathCat(defaultOutputFile, GetSourceFile());
302             ChangeExtension(defaultOutputFile, "c", defaultOutputFile);
303             SetOutputFile(defaultOutputFile);
304          }
305       }
306
307       if(!valid)
308          printf($"Syntax:\n   ecc [-t <target platform>] [-cpp <c preprocessor>] [-o <output>] [-symbols <outputdir>] [-I<includedir>]* [-isystem <sysincludedir>]* [-D<definition>]* -c <input>\n");
309       else
310       {
311          DualPipe cppOutput;
312          // TODO: Improve this
313          char command[MAX_F_STRING*3];
314          SetGlobalData(&globalData);
315          SetExcludedSymbols(&_excludedSymbols);
316          SetGlobalContext(globalContext);
317          SetCurrentContext(globalContext);
318          SetTopContext(globalContext);
319          SetDefines(&::defines);
320          SetImports(&imports);
321          SetInCompiler(true);
322          SetTargetPlatform(targetPlatform);
323          SetEchoOn(false);
324
325          privateModule = (Module)__ecere_COM_Initialize(true, 1, null);
326          SetPrivateModule(privateModule);
327
328          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint"), type = ProcessTypeString("unsigned int", false) });
329          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint64"), type = ProcessTypeString("unsigned int64", false) });
330          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint32"), type = ProcessTypeString("unsigned int", false) });
331          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint16"), type = ProcessTypeString("unsigned short", false) });
332          globalContext.types.Add((BTNode)Symbol { string = CopyString("byte"), type = ProcessTypeString("unsigned char", false) });
333
334          {
335             GlobalData data { fullName = CopyString("__thisModule"), dataTypeString = CopyString("Module"), module = privateModule };
336             data.key = (uint)data.fullName;
337             globalData.functions.Add((BTNode)data);
338          }
339
340          snprintf(command, sizeof(command), "%s%s -x c -E \"%s\"", cppCommand, cppOptions ? cppOptions : "", GetSourceFile());
341          command[sizeof(command)-1] = 0;
342          if((cppOutput = DualPipeOpen({ output = true }, command)))
343          {
344             char impFile[MAX_LOCATION];
345             ImportedModule module;
346             char mainModuleName[MAX_FILENAME];
347             int exitCode;
348             OldList * ast;
349
350             TempFile fileInput { };
351             SetFileInput(fileInput);
352
353             imports.Add((mainModule = ModuleImport { }));
354             SetMainModule(mainModule);
355
356             GetLastDirectory(GetSourceFile(), mainModuleName);
357
358 #if 0
359             // TEMP: UNTIL WE CAN HAVE PER SOURCE FILE PREPROCESSOR DEFINITIONS...
360             if(GetBuildingEcereCom() && 
361                !(strcmpi(mainModuleName, "instance.ec") && strcmpi(mainModuleName, "BinaryTree.ec") &&
362                strcmpi(mainModuleName, "dataTypes.ec") && strcmpi(mainModuleName, "OldList.ec") &&
363                strcmpi(mainModuleName, "String.ec") && strcmpi(mainModuleName, "BTNode.ec") &&
364                strcmpi(mainModuleName, "Array.ec") && strcmpi(mainModuleName, "AVLTree.ec") &&
365                strcmpi(mainModuleName, "BuiltInContainer.ec") && strcmpi(mainModuleName, "Container.ec") &&
366                strcmpi(mainModuleName, "CustomAVLTree.ec") && strcmpi(mainModuleName, "LinkList.ec") &&
367                strcmpi(mainModuleName, "List.ec") && strcmpi(mainModuleName, "Map.ec") &&
368                strcmpi(mainModuleName, "Mutex.ec")))
369                SetBuildingEcereComModule(true);
370             if(GetBuildingEcereCom() && 
371                !(strcmpi(mainModuleName, "instance.ec") && strcmpi(mainModuleName, "BinaryTree.ec") &&
372                /*strcmpi(mainModuleName, "dataTypes.ec") && strcmpi(mainModuleName, "OldList.ec") &&*/
373                /*strcmpi(mainModuleName, "String.ec") && */strcmpi(mainModuleName, "BTNode.ec") &&
374                strcmpi(mainModuleName, "Mutex.ec") && strcmpi(mainModuleName, "Thread.ec")))
375             //if(GetBuildingEcereCom() && !strcmpi(mainModuleName, "instance.ec"))
376                SetMemoryGuard(false);
377 #endif            
378
379             StripExtension(mainModuleName);
380             module = ImportedModule { name = CopyString(mainModuleName), type = moduleDefinition };
381             ::defines.AddName(module);
382
383             resetScanner();
384             while(!cppOutput.Eof())
385             {
386                char junk[4096];
387                int count = cppOutput.Read(junk, 1, 4096);
388                fileInput.Write(junk, 1, count);
389             }
390             exitCode = cppOutput.GetExitCode();
391             delete cppOutput;
392
393             fileInput.Seek(0, start);
394
395    #ifdef _DEBUG
396             // SetYydebug(true);
397    #endif
398
399             // Predeclare all classes
400             {
401                char symFile[MAX_FILENAME];
402                char symLocation[MAX_LOCATION];
403                ImportedModule module, next;
404
405                GetLastDirectory(GetSourceFile(), symFile);
406                ChangeExtension(symFile, "sym", symFile);
407
408                strcpy(symLocation, GetSymbolsDir());
409                PathCat(symLocation, symFile);
410                
411                // LoadSymbols(symLocation, normalImport, true);
412                LoadSymbols(symLocation, preDeclImport, false);
413                
414                for(module = ::defines.first; module; module = next)
415                {
416                   next = module.next;
417                   if(module.type == moduleDefinition && strcmpi(module.name, mainModuleName))
418                   {
419                      delete module.name;
420                      ::defines.Delete(module);
421                   }
422                }
423
424                if(!GetEcereImported() && !GetBuildingEcereCom())
425                   eModule_LoadStrict(privateModule, "ecereCOM", publicAccess /*privateAccess*/);
426             }
427
428             ParseEc();
429
430             CheckDataRedefinitions();
431
432             SetYydebug(false);
433             SetCurrentNameSpace(null);
434             SetDefaultNameSpace(null);
435             SetDeclMode(privateAccess);
436
437             delete fileInput;
438             SetFileInput(null);
439
440             ast = GetAST();
441
442             if(/*ast /*&& !parseError*/ /*&& */!exitCode)
443             {
444                ProcessDBTableDefinitions();
445
446                // *** PASS 0 - Register all classes, methods, properties and members ***
447                // ***          Build the constructors, destructors, properties as    ***
448                // ***          class functions                                       ***
449                PrePreProcessClassDefinitions();
450                ComputeModuleClasses(privateModule);
451                PreProcessClassDefinitions();
452
453                // For classes defined in this module...
454                ComputeModuleClasses(privateModule);
455
456                
457                // *** PASS 1 - Turn the class functions into functions               ***
458                // *** Write the RegisterModule (Register classes)                    ***
459                ProcessClassDefinitions();
460
461                // *** PASS 1.5 - Replace members by this.member, figure out types, do type checking / conversions
462                ComputeDataTypes();
463
464                // *** PASS 1.6 - Replace instantiations
465                ProcessInstantiations();
466
467                // *** PASS 2 - Replace Member Access ***
468                ProcessMemberAccess();
469
470                // *** PASS 3 - Replace pointers to objects by "Instance *" ***
471                ProcessInstanceDeclarations();
472
473                strcpy(impFile, GetSymbolsDir());
474                {
475                   char fileName[MAX_FILENAME];
476                   GetLastDirectory(GetSourceFile(), fileName);
477                   PathCat(impFile, fileName);
478                   ChangeExtension(impFile, "imp", impFile);
479                }
480                if(imports.first)
481                   OutputImports(impFile);
482                // For now use precomp to generate sym file only...
483
484                if(/*!strcmp(targetExt, "c") && */!this.exitCode)
485                {
486                   File output = FileOpen(GetOutputFile(), write);
487                   if(output)
488                   {
489                      //output.Printf("#include <ecereCOM.h>\n\n");
490
491                      // Temporary patch, fix with defines or something...
492                      /*
493                      if(!strstr(GetSourceFile(), "instance.ec"))
494                      {
495                         output.Printf("#if defined(__GNUC__) && defined(__WIN32__)\n");
496                         output.Printf("#include <x87inline.h>\n");
497                         output.Printf("#endif\n");
498                      }
499                      */
500                      /*output.Printf("#if defined(__GNUC__) \n");
501                         output.Printf("typedef long long int64;\n");
502                         output.Printf("typedef unsigned long long uint64;\n");
503                      output.Printf("#else\n");
504                         output.Printf("typedef __int64 int64;\n");
505                         output.Printf("typedef unsigned __int64 uint64;\n");
506                      output.Printf("#endif\n");*/
507                      output.Printf("#if defined(__GNUC__)\n");
508                         output.Printf("typedef long long int64;\n");
509                         output.Printf("typedef unsigned long long uint64;\n");
510                      output.Printf("#elif defined(__TINYC__)\n");
511                         output.Printf("#include <stdarg.h>\n");
512                         output.Printf("#define __builtin_va_list va_list\n");
513                         output.Printf("#define __builtin_va_start va_start\n");
514                         output.Printf("#define __builtin_va_end va_end\n");
515                         output.Printf("#ifdef _WIN32\n");
516                            output.Printf("#define strcasecmp stricmp\n");
517                            output.Printf("#define strncasecmp strnicmp\n");
518                            output.Printf("#define __declspec(x) __attribute__((x))\n");
519                         output.Printf("#endif\n");
520                         output.Printf("typedef long long int64;\n");
521                         output.Printf("typedef unsigned long long uint64;\n");
522                      output.Printf("#else\n");
523                         output.Printf("typedef __int64 int64;\n");
524                         output.Printf("typedef unsigned __int64 uint64;\n");
525                      output.Printf("#endif\n");
526                      /*output.Printf("#if defined(__GNUC__) || defined(__TINYC__)\n");
527                         output.Printf("typedef long long int64;\n");
528                         output.Printf("typedef unsigned long long uint64;\n");
529                      output.Printf("#elif defined(__TINYC__)\n");
530                      output.Printf("#else\n");
531                         output.Printf("typedef __int64 int64;\n");
532                         output.Printf("typedef unsigned __int64 uint64;\n");
533                      output.Printf("#endif\n");*/
534                      output.Printf("#ifdef __BIG_ENDIAN__\n");
535                         output.Printf("#define __ENDIAN_PAD(x) (8 - (x))\n");
536                      output.Printf("#else\n");
537                         output.Printf("#define __ENDIAN_PAD(x) 0\n");
538                      output.Printf("#endif\n");
539
540                      // NOTE: If anything is changed up there, the start outputLine must be updated in libec's output.c or Debugging lines will be wrong
541
542                      if(ast)
543                         OutputTree(ast, output);
544                      delete output;
545                   }
546                }
547                /*
548                else if(!strcmp(targetExt, "o"))
549                {
550                   // Compile right away
551                   File output = FileOpen(GetOutputFile(), Write);
552                   output.Printf("#include <ecereCOM.h>\n\n");
553                   OutputTree(ast, output);
554                   delete output;
555                }*/
556             }
557             else
558                this.exitCode = exitCode;
559
560             if(ast)
561             {
562                FreeASTTree(ast);
563             }
564          }
565
566          FreeContext(globalContext);
567          FreeExcludedSymbols(_excludedSymbols);
568
569          ::defines.Free(FreeModuleDefine);
570          imports.Free(FreeModuleImport);
571
572          FreeTypeData(privateModule);
573          FreeIncludeFiles();
574          FreeGlobalData(globalData);
575
576          delete privateModule;
577       }
578
579       delete cppCommand;
580       delete cppOptions;
581
582       /*for(c = 0; c<argc; c++)
583          delete argv[c];
584       delete argv;
585       */
586       SetSymbolsDir(null); // Free symbols dir
587
588       OutputIntlStrings();
589
590 #if defined(_DEBUG) && defined(__WIN32__)
591       if(exitCode || GetNumWarnings())
592          getch();
593 #endif
594    }
595 }