compiler: Fixed __declspec compiling issue on Linux; ide: Fixed crash on null workspace
[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       int targetBits = GetHostBits();
132
133       SetSymbolsDir("");
134
135       /*for(c = 0; c<this.argc; c++)
136       {
137          char * arg = this.argv[c];
138          int argLen = strlen(arg);
139
140          argv = renew argv char *[argc + 1];
141          argv[argc] = new char[argLen+1];
142          strcpy(argv[argc], arg);
143
144          while(argv[argc][argLen-1] == '\\' && c < this.argc-1)
145          {
146             int len;
147
148             c++;
149             arg = this.argv[c];
150             len = strlen(arg);
151             argv[argc] = renew argv[argc] char[argLen + len + 1];
152
153             argv[argc][argLen-1] = ' ';
154             strcpy(argv[argc] + argLen, arg);
155             argLen += len;
156          }
157          argc++;
158       }*/
159
160       for(c = 1; c<argc; c++)
161       {
162          char * arg = argv[c];
163          if(arg[0] == '-')
164          {
165             if(!strcmp(arg + 1, "m32") || !strcmp(arg + 1, "m64"))
166             {
167 #if defined(__WIN32__)
168                if(strcmp(arg + 1, "m64"))    // Until we set up MinGW-w64
169 #endif
170                {
171                   int argLen = strlen(arg);
172                   int newLen = cppOptionsLen + 1 + argLen;
173                   cppOptions = renew cppOptions char[newLen + 1];
174                   cppOptions[cppOptionsLen] = ' ';
175                   strcpy(cppOptions + cppOptionsLen + 1, arg);
176                   cppOptionsLen = newLen;
177                }
178                targetBits = !strcmp(arg + 1, "m32") ? 32 : 64;
179             }
180             else if(arg[1] == 'D')
181             {
182                int argLen = strlen(arg);
183                int newLen = cppOptionsLen + 1 + argLen;
184                cppOptions = renew cppOptions char[newLen + 1];
185                cppOptions[cppOptionsLen] = ' ';
186                strcpy(cppOptions + cppOptionsLen + 1, arg); 
187                cppOptionsLen = newLen;
188                if(!strcmp(arg, "-DBUILDING_ECERE_COM"))
189                   SetBuildingEcereCom(true);
190                else if(!strcmp(arg, "-DECERE_COM_MODULE"))
191                   SetBuildingEcereComModule(true);
192             }
193             else if(arg[1] == 'I')
194             {
195                int argLen = strlen(arg);
196                int newLen = cppOptionsLen + argLen + 3;
197                cppOptions = renew cppOptions char[newLen + 1];
198                cppOptions[cppOptionsLen] = ' ';
199                cppOptions[cppOptionsLen+1] = '-';
200                cppOptions[cppOptionsLen+2] = 'I';
201                cppOptions[cppOptionsLen+3] = '"';
202                strcpy(cppOptions + cppOptionsLen + 4, arg+2); 
203                cppOptions[newLen-1] = '\"';
204                cppOptions[newLen] = '\0';
205                cppOptionsLen = newLen;
206             }
207             else if(!strcmp(arg+1, "t"))
208             {
209                if(++c < argc)
210                   targetPlatform = argv[c];
211                else
212                   valid = false;
213             }
214             else if(!strcmp(arg+1, "cpp"))
215             {
216                if(++c < argc)
217                   cppCommand = CopyString(argv[c]);
218                else
219                   valid = false;
220             }
221             else if(!strcmp(arg+1, "o"))
222             {
223                if(!GetOutputFile() && c + 1 < argc)
224                {
225                   SetOutputFile(argv[c+1]);
226                   c++;
227                }
228                else
229                   valid = false;
230             }
231             else if(!strcmp(arg+1, "c"))
232             {
233                if(!GetSourceFile() && c + 1 < argc)
234                {
235                   SetSourceFile(argv[c+1]);
236                   c++;
237                }
238                else
239                   valid = false;
240             }
241             else if(!strcmp(arg+1, "isystem") || !strcmp(arg+1, "isysroot"))
242             {
243                if(c + 1 < argc)
244                {
245                   int argLen = strlen(arg);
246                   int arg1Len = strlen(argv[c+1]);
247                   int newLen = cppOptionsLen + argLen + arg1Len + 4;
248                   cppOptions = renew cppOptions char[newLen + 1];
249                   cppOptions[cppOptionsLen] = ' ';
250                   strcpy(cppOptions + cppOptionsLen + 1, arg); 
251                   cppOptions[cppOptionsLen+argLen+1] = ' ';
252                   cppOptions[cppOptionsLen+argLen+2] = '"';
253                   arg = argv[++c];
254                   strcpy(cppOptions + cppOptionsLen + argLen + 3, arg); 
255                   cppOptions[newLen-1] = '\"';
256                   cppOptions[newLen] = '\0';
257                   cppOptionsLen = newLen;
258                }
259                else
260                   valid = false;
261             }
262             else if(!strcmp(arg+1, "symbols"))
263             {
264                if(c + 1 < argc)
265                {
266                   SetSymbolsDir(argv[c+1]);
267                   c++;
268                }
269                else
270                   valid = false;
271             }
272             else if(!strcmp(arg+1, "memguard"))
273             {
274                SetMemoryGuard(true);
275             }
276             else if(!strcmp(arg+1, "defaultns"))
277             {
278                if(c + 1 < argc)
279                {
280                   SetDefaultNameSpace(argv[c+1]);
281                   //defaultNameSpaceLen = strlen(defaultNameSpace);
282                   c++;
283                }
284                else
285                   valid = false;
286             }
287             else if(!strcmp(arg+1, "strictns"))
288             {
289                SetStrictNameSpaces(true);
290             }
291             else if(!strcmp(arg+1, "nolinenumbers"))
292             {
293                SetOutputLineNumbers(false);
294             }
295          }
296          else
297             valid = false;
298       }
299       if(valid)
300       {
301          if(!cppCommand)
302             cppCommand = CopyString("gcc");
303          if(!GetSourceFile())
304             valid = false;
305          else if(!GetOutputFile())
306          {
307             strcpy(defaultOutputFile, "");
308             PathCat(defaultOutputFile, GetSourceFile());
309             ChangeExtension(defaultOutputFile, "c", defaultOutputFile);
310             SetOutputFile(defaultOutputFile);
311          }
312       }
313
314       if(!valid)
315          printf($"Syntax:\n   ecc [-t <target platform>] [-cpp <c preprocessor>] [-o <output>] [-symbols <outputdir>] [-I<includedir>]* [-isystem <sysincludedir>]* [-D<definition>]* -c <input>\n");
316       else
317       {
318          DualPipe cppOutput;
319          // TODO: Improve this
320          char command[MAX_F_STRING*3];
321          SetGlobalData(&globalData);
322          SetExcludedSymbols(&_excludedSymbols);
323          SetGlobalContext(globalContext);
324          SetCurrentContext(globalContext);
325          SetTopContext(globalContext);
326          SetDefines(&::defines);
327          SetImports(&imports);
328          SetInCompiler(true);
329          SetTargetPlatform(targetPlatform);
330          SetTargetBits(targetBits);
331          SetEchoOn(false);
332
333          privateModule = (Module)__ecere_COM_Initialize(true | ((targetBits == 64)?2:0), 1, null);
334          SetPrivateModule(privateModule);
335
336          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint"), type = ProcessTypeString("unsigned int", false) });
337          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint64"), type = ProcessTypeString("unsigned int64", false) });
338          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint32"), type = ProcessTypeString("unsigned int", false) });
339          globalContext.types.Add((BTNode)Symbol { string = CopyString("uint16"), type = ProcessTypeString("unsigned short", false) });
340          globalContext.types.Add((BTNode)Symbol { string = CopyString("byte"), type = ProcessTypeString("unsigned char", false) });
341
342          {
343             GlobalData data { fullName = CopyString("__thisModule"), dataTypeString = CopyString("Module"), module = privateModule };
344             data.key = (uintptr)data.fullName;
345             globalData.functions.Add((BTNode)data);
346          }
347
348          snprintf(command, sizeof(command), "%s%s -x c -E \"%s\"", cppCommand, cppOptions ? cppOptions : "", GetSourceFile());
349          command[sizeof(command)-1] = 0;
350          if((cppOutput = DualPipeOpen({ output = true }, command)))
351          {
352             char impFile[MAX_LOCATION];
353             ImportedModule module;
354             char mainModuleName[MAX_FILENAME];
355             int exitCode;
356             OldList * ast;
357
358             TempFile fileInput { };
359             SetFileInput(fileInput);
360
361             imports.Add((mainModule = ModuleImport { }));
362             SetMainModule(mainModule);
363
364             GetLastDirectory(GetSourceFile(), mainModuleName);
365
366 #if 0
367             // TEMP: UNTIL WE CAN HAVE PER SOURCE FILE PREPROCESSOR DEFINITIONS...
368             if(GetBuildingEcereCom() && 
369                !(strcmpi(mainModuleName, "instance.ec") && strcmpi(mainModuleName, "BinaryTree.ec") &&
370                strcmpi(mainModuleName, "dataTypes.ec") && strcmpi(mainModuleName, "OldList.ec") &&
371                strcmpi(mainModuleName, "String.ec") && strcmpi(mainModuleName, "BTNode.ec") &&
372                strcmpi(mainModuleName, "Array.ec") && strcmpi(mainModuleName, "AVLTree.ec") &&
373                strcmpi(mainModuleName, "BuiltInContainer.ec") && strcmpi(mainModuleName, "Container.ec") &&
374                strcmpi(mainModuleName, "CustomAVLTree.ec") && strcmpi(mainModuleName, "LinkList.ec") &&
375                strcmpi(mainModuleName, "List.ec") && strcmpi(mainModuleName, "Map.ec") &&
376                strcmpi(mainModuleName, "Mutex.ec")))
377                SetBuildingEcereComModule(true);
378             if(GetBuildingEcereCom() && 
379                !(strcmpi(mainModuleName, "instance.ec") && strcmpi(mainModuleName, "BinaryTree.ec") &&
380                /*strcmpi(mainModuleName, "dataTypes.ec") && strcmpi(mainModuleName, "OldList.ec") &&*/
381                /*strcmpi(mainModuleName, "String.ec") && */strcmpi(mainModuleName, "BTNode.ec") &&
382                strcmpi(mainModuleName, "Mutex.ec") && strcmpi(mainModuleName, "Thread.ec")))
383             //if(GetBuildingEcereCom() && !strcmpi(mainModuleName, "instance.ec"))
384                SetMemoryGuard(false);
385 #endif            
386
387             StripExtension(mainModuleName);
388             module = ImportedModule { name = CopyString(mainModuleName), type = moduleDefinition };
389             ::defines.AddName(module);
390
391             resetScanner();
392             while(!cppOutput.Eof())
393             {
394                char junk[4096];
395                int count = cppOutput.Read(junk, 1, 4096);
396                fileInput.Write(junk, 1, count);
397             }
398             exitCode = cppOutput.GetExitCode();
399             delete cppOutput;
400
401             fileInput.Seek(0, start);
402
403    #ifdef _DEBUG
404             // SetYydebug(true);
405    #endif
406
407             // Predeclare all classes
408             {
409                char symFile[MAX_FILENAME];
410                char symLocation[MAX_LOCATION];
411                ImportedModule module, next;
412
413                GetLastDirectory(GetSourceFile(), symFile);
414                ChangeExtension(symFile, "sym", symFile);
415
416                strcpy(symLocation, GetSymbolsDir());
417                PathCat(symLocation, symFile);
418                
419                // LoadSymbols(symLocation, normalImport, true);
420                LoadSymbols(symLocation, preDeclImport, false);
421                
422                for(module = ::defines.first; module; module = next)
423                {
424                   next = module.next;
425                   if(module.type == moduleDefinition && strcmpi(module.name, mainModuleName))
426                   {
427                      delete module.name;
428                      ::defines.Delete(module);
429                   }
430                }
431
432                if(!GetEcereImported() && !GetBuildingEcereCom())
433                   eModule_LoadStrict(privateModule, "ecereCOM", publicAccess /*privateAccess*/);
434             }
435
436             ParseEc();
437
438             CheckDataRedefinitions();
439
440             SetYydebug(false);
441             SetCurrentNameSpace(null);
442             SetDefaultNameSpace(null);
443             SetDeclMode(privateAccess);
444
445             delete fileInput;
446             SetFileInput(null);
447
448             ast = GetAST();
449
450             if(/*ast /*&& !parseError*/ /*&& */!exitCode)
451             {
452                ProcessDBTableDefinitions();
453
454                // *** PASS 0 - Register all classes, methods, properties and members ***
455                // ***          Build the constructors, destructors, properties as    ***
456                // ***          class functions                                       ***
457                PrePreProcessClassDefinitions();
458                ComputeModuleClasses(privateModule);
459                PreProcessClassDefinitions();
460
461                // For classes defined in this module...
462                ComputeModuleClasses(privateModule);
463
464                
465                // *** PASS 1 - Turn the class functions into functions               ***
466                // *** Write the RegisterModule (Register classes)                    ***
467                ProcessClassDefinitions();
468
469                // *** PASS 1.5 - Replace members by this.member, figure out types, do type checking / conversions
470                ComputeDataTypes();
471
472                // *** PASS 1.6 - Replace instantiations
473                ProcessInstantiations();
474
475                // *** PASS 2 - Replace Member Access ***
476                ProcessMemberAccess();
477
478                // *** PASS 3 - Replace pointers to objects by "Instance *" ***
479                ProcessInstanceDeclarations();
480
481                strcpy(impFile, GetSymbolsDir());
482                {
483                   char fileName[MAX_FILENAME];
484                   GetLastDirectory(GetSourceFile(), fileName);
485                   PathCat(impFile, fileName);
486                   ChangeExtension(impFile, "imp", impFile);
487                }
488                if(imports.first)
489                   OutputImports(impFile);
490                // For now use precomp to generate sym file only...
491
492                if(/*!strcmp(targetExt, "c") && */!this.exitCode)
493                {
494                   File output = FileOpen(GetOutputFile(), write);
495                   if(output)
496                   {
497                      //output.Printf("#include <ecereCOM.h>\n\n");
498
499                      // Temporary patch, fix with defines or something...
500                      /*
501                      if(!strstr(GetSourceFile(), "instance.ec"))
502                      {
503                         output.Printf("#if defined(__GNUC__) && defined(__WIN32__)\n");
504                         output.Printf("#include <x87inline.h>\n");
505                         output.Printf("#endif\n");
506                      }
507                      */
508                      /*output.Printf("#if defined(__GNUC__) \n");
509                         output.Printf("typedef long long int64;\n");
510                         output.Printf("typedef unsigned long long uint64;\n");
511                      output.Printf("#else\n");
512                         output.Printf("typedef __int64 int64;\n");
513                         output.Printf("typedef unsigned __int64 uint64;\n");
514                      output.Printf("#endif\n");*/
515                      output.Printf("#if defined(__GNUC__)\n");
516                         output.Printf("typedef long long int64;\n");
517                         output.Printf("typedef unsigned long long uint64;\n");
518                      output.Printf("#elif defined(__TINYC__)\n");
519                         output.Printf("#include <stdarg.h>\n");
520                         output.Printf("#define __builtin_va_list va_list\n");
521                         output.Printf("#define __builtin_va_start va_start\n");
522                         output.Printf("#define __builtin_va_end va_end\n");
523                         output.Printf("#ifdef _WIN32\n");
524                            output.Printf("#define strcasecmp stricmp\n");
525                            output.Printf("#define strncasecmp strnicmp\n");
526                            output.Printf("#define __declspec(x) __attribute__((x))\n");
527                         output.Printf("#else\n");
528                            output.Printf("#define __declspec(x)\n");
529                         output.Printf("#endif\n");
530                         output.Printf("typedef long long int64;\n");
531                         output.Printf("typedef unsigned long long uint64;\n");
532                      output.Printf("#else\n");
533                         output.Printf("typedef __int64 int64;\n");
534                         output.Printf("typedef unsigned __int64 uint64;\n");
535                      output.Printf("#endif\n");
536                      /*output.Printf("#if defined(__GNUC__) || defined(__TINYC__)\n");
537                         output.Printf("typedef long long int64;\n");
538                         output.Printf("typedef unsigned long long uint64;\n");
539                      output.Printf("#elif defined(__TINYC__)\n");
540                      output.Printf("#else\n");
541                         output.Printf("typedef __int64 int64;\n");
542                         output.Printf("typedef unsigned __int64 uint64;\n");
543                      output.Printf("#endif\n");*/
544                      output.Printf("#ifdef __BIG_ENDIAN__\n");
545                         output.Printf("#define __ENDIAN_PAD(x) (8 - (x))\n");
546                      output.Printf("#else\n");
547                         output.Printf("#define __ENDIAN_PAD(x) 0\n");
548                      output.Printf("#endif\n");
549                      output.Printf("#include <stdint.h>\n");
550
551                      // NOTE: If anything is changed up there, the start outputLine must be updated in libec's output.c or Debugging lines will be wrong
552
553                      if(ast)
554                         OutputTree(ast, output);
555                      delete output;
556                   }
557                }
558                /*
559                else if(!strcmp(targetExt, "o"))
560                {
561                   // Compile right away
562                   File output = FileOpen(GetOutputFile(), Write);
563                   output.Printf("#include <ecereCOM.h>\n\n");
564                   OutputTree(ast, output);
565                   delete output;
566                }*/
567             }
568             else
569                this.exitCode = exitCode;
570
571             if(ast)
572             {
573                FreeASTTree(ast);
574             }
575          }
576
577          FreeContext(globalContext);
578          FreeExcludedSymbols(_excludedSymbols);
579
580          ::defines.Free(FreeModuleDefine);
581          imports.Free(FreeModuleImport);
582
583          FreeTypeData(privateModule);
584          FreeIncludeFiles();
585          FreeGlobalData(globalData);
586
587          delete privateModule;
588       }
589
590       delete cppCommand;
591       delete cppOptions;
592
593       /*for(c = 0; c<argc; c++)
594          delete argv[c];
595       delete argv;
596       */
597       SetSymbolsDir(null); // Free symbols dir
598
599       OutputIntlStrings();
600
601 #if defined(_DEBUG) && defined(__WIN32__)
602       if(exitCode || GetNumWarnings())
603          getch();
604 #endif
605    }
606 }