EJC (C-Compiler) experiments

Anything QL Software or Programming Related.
User avatar
bwinkel67
QL Wafer Drive
Posts: 1187
Joined: Thu Oct 03, 2019 2:09 am

Re: EJC (C-Compiler) experiments

Post by bwinkel67 »

ql_freak wrote: Unfortunately there's one strcpy() function used (often), which I don't understand:

Code: Select all

int   compile(s)
char  *s;
{
   char  b[256];
   AJOB  jobs[1];
   int   retcode;
   char  *strcat(),*strcpy();
   void  viewfile(),deletefile();
   struct stat sb1,sb2;
   char  *cp;
   char  m[20];

   if( dflag )
      if( stat( strcat(strcpy(b,s),"_o"),&sb2 )==0 )
      /*               ^^^^^^^^^^^ */
 /* parameter s is declared in main with: char *s[32]; i. e. array of 32 pointers to char. It is initialised
 in a for loop with: s[sc++] = argv[i]+1; sc and i are declared as int. Then compile is called with:
   ec += compile(s[i]); where ec is the error count */
So this code is taking the arguments from the command line (i.e. s*[32] allows for 32 strings where each string I'm guessing is a filename) which are the source files you can compile, and one-by-one passing them into compile (for, I assume, compilation). The strcpy takes the source file (which I think you said should not have a _c extension) and adds the _c extension...so it first copies it into b to not overwrite the original s structure (arrays in C are passed by reference) and then concatenates "_c" to it. Then it seems to do a stat command which I"m guessing sees if the file exists. Since b is a local array of 256 characters it is defined on the stack and only persists within the compile function (so it's a temporary place to store stuff).

Note that strcpy is defined: char *strcpy(char *dest, const char *src)

If the command line can take in arguments besides source filenames, I'm guessing that when the "if (stat...)" fails there is an else to it that checks for the arguments, i.e. things that are preceded by -.

One weirdness is that the compile function prototypes strcat and strcpy within its local parameters...usually you stick those in a header file and usually those are predefined in a string_h (string.h in non-QL parlance) since they are implemented in a standard library used by the C compiler. In Digital 'C' SE these are prototyped, I believe, in stdio_h and the library is std_lib (which is pretty standard). Perhaps just a unique quirk of the coder who wrote compile...dunno.


User avatar
ql_freak
Gold Card
Posts: 353
Joined: Sun Jan 18, 2015 1:29 am

Re: EJC (C-Compiler) experiments

Post by ql_freak »

bwinkel67 wrote:
ql_freak wrote: Unfortunately there's one strcpy() function used (often), which I don't understand:
Note that strcpy is defined: char *strcpy(char *dest, const char *src)
Aarrrgggghhhhh! I't's long ago I used C, I now use always C++, where there is normally no need for strcpy (C++ has real strings), so I thought the second parameter is the destination :-( Thank You! Now it's clear.

Conclusion: If all else fails, read the manual ;-)


http://peter-sulzer.bplaced.net
GERMAN! QL-Download page also available in English: GETLINE$() function, UNIX-like "ls" command, improved DIY-Toolkit function EDLINE$ - All with source. AND a good Python 3 Tutorial (German) for Win/UNIX :-)
User avatar
ql_freak
Gold Card
Posts: 353
Joined: Sun Jan 18, 2015 1:29 am

Re: EJC (C-Compiler) experiments

Post by ql_freak »

I now have a first version of the cc compiler driver, which prints it's output (currently just pass/phase 1) to a listfile on RAM1_. I have named it ecc. It's not perfect: You can currently not use another device as RAM1_ for the listing file, and if the compiled file is a fully qualified name (with DEVICE as WIN1_ in front) the device name of the original file comes after the RAM1_ (e.g. when compiling RAM1_hello_c the listing file is RAM1_RAM1_hello_Lst1). Unfortunately the max length for a redirected file in Lattice C compiler seems to be 31 chars. If the redirected filename is longer, the redirected outputfile (>redirected_output_file_name) is NOT written :-( I have now added a note into my original MCDK manual - so now it's "saved" for me. But I think it's not too hard to correct this(1). I think I will make a fixed name, most probably RAM1_Qlc1Err_txt, which has the advantage that it can be "executed" from Files and will be opened in your configured favourite editor from FileInfo2. With the help of SuperBASIC or a Shell it's still be possible to rename this name to what you want.

So now I can compile ecc_c with:

Code: Select all

ex'ecc',#2,#1;'ecc ecc':PAUSE 100:VIEW#3,'RAM1_ecc_Lst1
and get the error messages in CON channel #3 :-)

BTW the Lattice Compiler has support for function prototypes (albeit in a different syntax as ANSI C), unfortunately the library header files are not prototyped (in original Metacomco C Development Kit they were prototyped as far as I can remember). The Syntax is (e.g.):

myfunc(char*, int); /* function prototype Lattice style */

myfunc(buf, length) /* function definition, KR style */
char* buf;
int length
{ ... }

For developing C and assembler I normally use MicroEMACS (V4.0) and have now detected, that it supports Syntax Hilighting :-))) SUPERB and a great help. I had to correct the colour for comments (ME variable $hilight4) in my emacs_rc file (it was white, and my background colour for ME is white). MicroEMACS is really a superb editor and the QDOS implementation (with full Pointer Environment support, menus, scrap, Menu_rext, FileInfo2, ...) is one of the best (I have used it long in a Windows 3.1 version, and the QDOS version is at least as good plus syntax hilighting). The only other editor for QDOS I know, which has similar capabilities is DME, but it has no Pointer Environment support (and does not support real tabs, ME is probably the only editor supporting real tabs on QDOS).
--
1) Of course the length limit of 31 (is 32 bytes with the trailing ZERO of C-[pseudo]strings) cannot be changed (we have no source code of the Lattice compiler), but it may be fixed with the help of the compiler driver, e.g. truncating the name, before passing it after the '>' to the Lattice compiler. As I also have a copy of PDQL C which also uses the Lattice compiler (but a newer version from the Atari ST; PDQL C has an emulator for ST TOS programs), I will try, if it is possible to use EJC with the Atari Lattice C compiler.


http://peter-sulzer.bplaced.net
GERMAN! QL-Download page also available in English: GETLINE$() function, UNIX-like "ls" command, improved DIY-Toolkit function EDLINE$ - All with source. AND a good Python 3 Tutorial (German) for Win/UNIX :-)
User avatar
Peter
QL Wafer Drive
Posts: 1953
Joined: Sat Jan 22, 2011 8:47 am

Re: EJC (C-Compiler) experiments

Post by Peter »

What is the point in using this compiler? Why not C68 or QDOS-GCC?

I've been using another ancient compiler called PDQC, but the only reason for that was truely relocatable code generation.


Derek_Stewart
Font of All Knowledge
Posts: 3928
Joined: Mon Dec 20, 2010 11:40 am
Location: Sunny Runcorn, Cheshire, UK

Re: EJC (C-Compiler) experiments

Post by Derek_Stewart »

Hi,

I have a disk with the full workable version of EJC, which will only work if Metacomco C development system is integrated into EJC.

Since Metacomco C is still commercial and can not be distributed, unless the status has changed.

As Peter indicates, C68 is more developed and better supported.

Maybe a more better question would be, to integrate Classes into C68, sort of C++


Regards,

Derek
User avatar
bwinkel67
QL Wafer Drive
Posts: 1187
Joined: Thu Oct 03, 2019 2:09 am

Re: EJC (C-Compiler) experiments

Post by bwinkel67 »

The argument made by Peter Sulzer is that EJC creates reentrant executable code as had Metacomco C (BTW,I pointed out that so does little old Digital 'C' SE). Peter Graf states that he uses PDQC for creating truly relocatable code. So first off, is there a difference between reenrant and relocatable code? In standard parlance their shouldn't as reentrant means that multiple copies of program can be run and thus they are not tied to an absolute address and so are relocatable (i.e. programs are reentrant if you can execute more than one copy at the same time and they remain independent of each other, save perhaps some file accesses, and functions are reentrant if you can run multiple threads...) -- of course assuming the meaning of computing terms can be dangerous :)

So my question then becomes why does C68 not offer to generate reentrant/relocatable code? If you generate a QDOS executable in C68, are you not able to "exec" two copies independent of each other? Seems to me that this would be an important component of a compiler.


User avatar
tofro
Font of All Knowledge
Posts: 2685
Joined: Sun Feb 13, 2011 10:53 pm
Location: SW Germany

Re: EJC (C-Compiler) experiments

Post by tofro »

bwinkel67 wrote:The argument made by Peter Sulzer is that EJC creates reentrant executable code as had Metacomco C (BTW,I pointed out that so does little old Digital 'C' SE). Peter Graf states that he uses PDQC for creating truly relocatable code. So first off, is there a difference between reenrant and relocatable code?
Of course. But first let's correct terminology a bit: Metacomco C and its derivates can create position-independent code - That is code that simply doesn't need to be runtime-relocated, because it can run unmodified at any load address. Even C68 code is relocatable, as the startup code relocates all absolute addresses generated relative to the load address (by runtime-relocation). That, however, makes it non-reentrant (because it modifies its own code which is no good for the second job that tries to run on the very same code).
bwinkel67 wrote: In standard parlance their shouldn't as reentrant means that multiple copies of program can be run and thus they are not tied to an absolute address and so are relocatable (i.e. programs are reentrant if you can execute more than one copy at the same time and they remain independent of each other, save perhaps some file accesses, and functions are reentrant if you can run multiple threads...) -- of course assuming the meaning of computing terms can be dangerous :)
Well, not quite. Reentrance means that the very same piece of code in memory (not a copy of it) is being used to run two or more jobs. Of course you can perfectly well run two copies of the same 100k C68 program in QDOSMSQ, occupying 200k of code space. When you do, however, instruct HOTKEY System II to run two jobs on the same 100k of C68 code - They will crash because the first job already modified the code in memory by relocating it. Something which works absolutely well with with position-independent code written in machine code or other languages that produce "clean" (in Tony Tebby parlance this means: not self-modifying) code. Hotkey System 2 Thus allows multiple jobs running on the very same instructions in memory - Only the data segments are specific to each job.
bwinkel67 wrote: So my question then becomes why does C68 not offer to generate reentrant/relocatable code? If you generate a QDOS executable in C68, are you not able to "exec" two copies independent of each other? Seems to me that this would be an important component of a compiler.
Q68 in fact has the option to produce position-independent code. It just doesn't work but rather crashes the compiler, at least in my experience. (If interested, have a look at the codemodel=small, datamodel=small and regdata=ax command line options)

As you see from the above, it can also perfectly well produce relocatable code. But that makes it non-reentrant because of the runtime-relocation and thus self-modifying code.


ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
User avatar
bwinkel67
QL Wafer Drive
Posts: 1187
Joined: Thu Oct 03, 2019 2:09 am

Re: EJC (C-Compiler) experiments

Post by bwinkel67 »

So from WikiPedia on reentrancy:

...a computer program is called reentrant if multiple invocations can safely run concurrently.

It then reinforces it with its 2nd (of 3) rule on reentrancy:

Reentrant code may not modify itself.
The operating system might allow a process to modify its code. There are various reasons for this (e.g., blitting graphics quickly) but this would cause a problem with reentrancy, since the code might not be the same next time. It may, however, modify itself if it resides in its own unique memory. That is, if each new invocation uses a different physical machine code location where a copy of the original code is made, it will not affect other invocations even if it modifies itself during execution of that particular invocation (thread).

So two executables loaded into their own memory are considered reentrant. But...other than terminology, it does bring up feature issues that some compilers offer (EJC, Metcamoco C, PDQC) that others don't, namely being able to generate pure relocatable code that runs into less problems with other systems. It looks like C68 doesn't do that (or is currently buggy causing crashes) and I have no idea if Digital 'C' SE does either. C68 seems to be the most popular compiler so I'm surprised it hasn't been fixed.

On a separate note, I don't really understand what HOTKEY is trying to do when running "two jobs on the same 100k of C68 code" as it sounds like it is trying to save memory by not loading a separate 100K for the second job and just allocating separate space for a stack and sharing the common heap? I recall there being a HOTCHP call and then one similar (HOTRES?) that dealt with different memory addressing. I would imagine if HOTKEY is used similar to how "Ctrl C" is used to cycle through running programs but instead of a linear list you can get to one specifically, then why not just point to where each program is in memory and not worry about reentrancy? HOTKEY almost reminds me of the original Mac Finder that couldn't run the same program multiple times (unless you copied and renamed it I believe).


Derek_Stewart
Font of All Knowledge
Posts: 3928
Joined: Mon Dec 20, 2010 11:40 am
Location: Sunny Runcorn, Cheshire, UK

Re: EJC (C-Compiler) experiments

Post by Derek_Stewart »

Hi,

Can you give an example of reentrant code, so that a comparison can be made.


Regards,

Derek
User avatar
ql_freak
Gold Card
Posts: 353
Joined: Sun Jan 18, 2015 1:29 am

Re: EJC (C-Compiler) experiments

Post by ql_freak »

Peter wrote:What is the point in using this compiler? Why not C68 or QDOS-GCC?

I've been using another ancient compiler called PDQC, but the only reason for that was truely relocatable code generation.
What is truely relocatable code? I think relocation means, that when the code is loaded, adresses of e.g. absolute jumps are replaced, so that the program can run, at the address where it is loaded. I have a copy of PDQC also, but afaik it doesn't create reentrant, ROMable code like EJC. The advantage is, that it uses the newer Atari ST version of the Lattice C compiler, which runs on QDOS thanks to a TOS emulator(1), delivered with PDQC (which IMHO has never been officially available).

I'm afraid the C68 compiler cannot create reentrant code. But even if it can, it would be useless, as the libraries are not created with reentrant code. The same problem ist true for Metacomco C development kit. Albeit it's Compiler (Lattice C) can produce reentrant code, the runtime library is not reentrant, so that you could not use the compiler switches from Lattice to create reentrant code. In EJC all the libraries are compiled with the switches to produce reentrant code.The disadvantage: The size for static data is limited to 64 K and calls to functions are limited to +/- 32 kByte.
--
1) With this emulator Atari ST command line programs can run under QDOS


http://peter-sulzer.bplaced.net
GERMAN! QL-Download page also available in English: GETLINE$() function, UNIX-like "ls" command, improved DIY-Toolkit function EDLINE$ - All with source. AND a good Python 3 Tutorial (German) for Win/UNIX :-)
Post Reply