Back to heater, I think what we have with Catalina is this amazing piece of code that is being greatly under utilised at the moment. BDSC is great, but it exists in CP/M so it is limited by the 64k memory limit. Catalina breaks out of this limit and can run free with as much ram as you want to throw at it.
So my generic idea is to somehow leverage the power of Catalina into other languages. Ross has stuck with ANSI standards and this means at least we do have a standard.
Qt is great but even a "hello world" seems to have one non ANSI line of code in it. Maybe it will end up the only one but it is mildly concerning in terms of standards. And look, I can't resist, I can feel a rant coming on, here it comes... /rant/ why, oh why, with a simple .exe can't they wrap up the .dll as well? No-one else ever is going to use that .dll. The .exe is not the compiled program. It is half the compiled program. How hard can it be to produce a single executable file?? /end rant/
So, back to the real world, BCX produces some somewhat hybrid code, but Ross has already shown that it can be converted to ANSI C. In particular, BCX can include raw C code in a Basic program, so it can be possible to write simple C functions in standard ANSI C to replace non ANSI C produced by the converter.
Where this could take us is very flexible code that can run on the Propeller, on a PC and on Linux. And Zog? I think that is a worthy goal worth pursuing.
So what I want to do is write a BCX to ANSI C converter, and I want to write that in ANSI C. Which I might choose to write in Basic first!
So my next little quest is for a simple C compiler that can run the same code Catalina is running.
Tiny C can produce a complete self contained .exe from this
Dumb question here, but can Catalina produce code that can run on a PC?
If not, what I would like is a simple C compiler that can take a program and can run on multiple platforms. If we stick to ANSI C, Catalina is that program for the propeller. Maybe GCC or Qt can do it for the PC. Not sure about linux. TinyC works for me on a PC but what about other OS'?
Don't worry I'm only debating the LMM issue for fun.
Now to business...
You really don't want to be getting your GCC from gnu.org. They have the source for it...but then you would need to compile it into a working compiler...but then you would need a working GCC to compile it... but then....
Normally Linux users get their GCC along with the OS.
You already have a perfectly good C89 compliant GCC C compiler on your machine. It's in the Qt IDE. Just write C89 standard code into there and it will compile and run just fine.
Have a look at "compile output" (look for the "build issues" drop down menu. I'm sure you will see the QT IDE is running a mingw version of GCC. You will be able to see it's path there. Then you can use it from the command line as a regular C compiler. (No funny command line switches added by the QT IDE) and no C++ or Qt libs involved.
Don't get me wrong I have the highest respect for Ross and Catalina, it is an amazing piece of work that I hope to see more widely adopted.
BDSC is, well, just for fun.
Using Catalina to enable other language support is an excellent idea. Ross already has Lua for example. BASIC would be welcome by many. A standards compliant C for the basis of these things is essential.
There is nothing mildly concerning about standards with Qt. It's just C++ not C.
As for dll's. A valid rant. But consider on my Linux box those shared libs are actually used by my entire GUI desktop and a bunch of apps. We will find a way to build a statically linked self contained Qt executable for Windows.
Where this could take us is very flexible code that can run on the Propeller, on a PC and on Linux. And Zog? I think that is a worthy goal worth pursuing.
Zog thinks this is an excellent idea as well. By the way, that's what C is all about and why everyone and his dog want's C on the Prop.
So my next little quest is for a simple C compiler that can run the same code Catalina is running. Dumb question here, but can Catalina produce code that can run on a PC?
I wont respond to each point in your emails individually (don't you guys ever sleep?). But here are some points, in no particular order ....
Heater and I will no doubt resume the LMM argument periodocally. Neither of us really expects to win - it's the argument that counts. Winning is less important than scoring a good point here and there
I use the MinGW (and MSYS) distribution of gcc for Windows. Some details are given in the Catalina reference manual. On Linux (as heater points out) gcc is nearly always included - or is downloadable as an easily installable package. Don't try and compile it from scratch!
There's no need to port Catalina to Windows (or Linux) - just use LCC instead. If you need a set of ANSI C libraries, you can use the Amsterdam Compiler Kit C libraries (these are what the Catalina libraries are based on). Or you can use LCC-Win32 (this is a compiler based on LCC - it is free for non-commercial use but not open source).
I always intended Catalina to be used as the basis for other languages for the Propeller - I just never seem to get time to do any work on them! You can either translate them to C and then use Catalina to compile them (as Dr_A is doing, or Lua or Pascal or Dumbo Basic does) or else compile them to PASM and then just make use of the Catalina targets, LMM kernel and other support tools - i.e. loaders, libraries etc. This latter technique has not yet been exploted by anyone (including me!) but is likely to give much faster results than using C as an intermediate language.
I would like to repackage Catalina with pre-compiled "armel" binaries for the Z2. Do I have your permission?
Hi Martin,
Thanks for asking - by all means include it. If you are going to include release 2.9, please also include the latest C3 patch, which also adds debugger support for all platforms. I have just added a copy of this patch to the Catalina Source Forge site (along with the 2.9 distribution files).
For future reference (and for others who may want to do the same) you don't really need to ask my permission. Since Catalina is open source, you just need to comply with the various license terms.
For the technically minded, these are the LGPL, GPL & MIT licenses, plus the two special ones for LCC and the Amsterdam Compiler Kit C libraries - but all these licenses permit redistribution provided their license conditions are preserved intact in the redistribution.
I've taken all the code so far and automated it. Rewriting an IDE for Qt is a little bit daunting at the moment so I'm doing this with vb.net because I can code this much quicker. However, I've written the code in such a way that it makes multiple passes through the .c file and each time makes a few changes and saves as a new file. So this should be the sort of code that is easier to port over to a console C application, and/or other code that runs on Linux and Windows.
Not sure if there is a Basic program that runs on both??
In any case, one thing that is nice about converting the output of BCX into C89 is that it compiles with TinyC. So it is getting to the stage of being possible to write code in Basic and translate it to something that will run on the propeller and on multiple platforms.
I put in some syntax highlighting.
This isn't finished and obviously every instruction will need to be tested, but the code below does test out a few key concepts - eg replacing lines with new lines, inserting new code, searching for code and replacing with other code that is bigger or smaller.
As an aside, see the second screenshot,
typedef unsigned char UCHAR;
should that be in the section System Variables? Or another section?
It sort of looks a bit lonely up there with the #includes.
vb.net code below:
Sub RunBCX()
Dim Location As New Process
Dim i As Integer
Dim Lineoftext As String
' save the file
RichTextBox4.SaveFile("C:\Program Files\Catalina\Demos\" + BigBasicFile, RichTextBoxStreamType.PlainText)
' copy to Cat1.bas
FileCopy("C:\Program Files\Catalina\Demos\" + BigBasicFile, "C:\Program Files\Catalina\Demos\Cat1.bas")
' copy cat1.bas to BCX directory
FileCopy("C:\Program Files\Catalina\Demos\Cat1.bas", "C:\Program Files\BCX\Bin\Cat1.bas")
' create a batch file
FileOpen(1, "C:\Program Files\BCX\Bin\Cat.bat", OpenMode.Output)
PrintLine(1, "BC cat1.bas")
If CompilePause = True Then
PrintLine(1, "pause") ' leaves batch file window open so can see errors
End If
FileClose(1)
' run BC and convert to cat1.c
Location.StartInfo.FileName = "cat.bat"
Location.StartInfo.WorkingDirectory = "C:\Program Files\BCX\Bin"
Location.Start() ' shell the startup file
Do
' wait till batch file finishes
Loop Until Location.HasExited = True
' now start the multipass editing process
' step 1 - remove all the windows #includes
i = 0
FileOpen(1, "C:\Program Files\BCX\Bin\Cat1.c", OpenMode.Input)
FileOpen(2, "C:\Program Files\BCX\Bin\Cat2.c", OpenMode.Output)
While EOF(1) = False
Lineoftext = LineInput(1)
If i > 0 Then i += 1 ' increment the counter
If Lineoftext = "// End of Object/Import Libraries To Search" Then
i = 1 ' start a counter
End If
If i > 3 Then
PrintLine(2, Lineoftext) ' save this line
End If
End While
FileClose(1)
FileClose(2)
' step 2 - add in the essential #includes
' later might not include all of these if running not in external memory
' list of catalina .h files is C:\Program Files\catalina\source\lib\include
FileOpen(1, "C:\Program Files\BCX\Bin\Cat2.c", OpenMode.Input)
FileOpen(2, "C:\Program Files\BCX\Bin\Cat3.c", OpenMode.Output) ' save as cat3.c
PrintLine(2, "#include <stdio.h>")
PrintLine(2, "#include <stdlib.h>")
PrintLine(2, "#include <string.h>")
PrintLine(2, "#include <math.h>")
PrintLine(2, "#include <ctype.h>")
PrintLine(2, "#include <errno.h>")
PrintLine(2, "#include <float.h>")
PrintLine(2, "#include <inttypes.h>")
PrintLine(2, "#include <limits.h>")
PrintLine(2, "#include <mathconst.h>")
PrintLine(2, "")
' and possibly some more #includes
PrintLine(2, "typedef unsigned char UCHAR;") ' so UCHAR works
While EOF(1) = False
Lineoftext = LineInput(1) ' read the line
PrintLine(2, Lineoftext) ' save this line
End While
FileClose(1)
FileClose(2)
' step 3 - replace some string handling functions
i = -1
FileOpen(1, "C:\Program Files\BCX\Bin\Cat3.c", OpenMode.Input)
FileOpen(2, "C:\Program Files\BCX\Bin\Cat4.c", OpenMode.Output)
While EOF(1) = False
Lineoftext = LineInput(1)
If i <> -1 Then i += 1 ' increment the counter
If Lineoftext = "char *left (char *S, int length)" Then
i = 0 ' start the counter and stop saving lines
End If
If i = 8 Then ' add in new code - solution thanks to Kuroneko
PrintLine(2, "char *left (char *S, int length)")
PrintLine(2, "{")
PrintLine(2, " char *strtmp;")
PrintLine(2, " register int tmplen = strlen(S);")
PrintLine(2, " if(length<1) return BCX_TmpStr(1);")
PrintLine(2, " if(length<tmplen) tmplen=length;")
PrintLine(2, " strtmp = BCX_TmpStr(tmplen);")
PrintLine(2, " return (char*)memcpy(strtmp,S,tmplen);")
PrintLine(2, "}")
i = -1 ' reset the counter
End If
' and replace one line for mid - can't define values in C89 like this
If Lineoftext = "char* mid (char*, int, int=-1);" Then
Lineoftext = "char* mid (char*, int, int);"
End If
If i = -1 Then PrintLine(2, Lineoftext) ' save this line
End While
FileClose(1)
FileClose(2)
' step 4 - add in RossHs strupr code
FileOpen(1, "C:\Program Files\BCX\Bin\Cat4.c", OpenMode.Input)
FileOpen(2, "C:\Program Files\BCX\Bin\Cat5.c", OpenMode.Output) ' save as cat3.c
While EOF(1) = False
Lineoftext = LineInput(1) ' read the line
If Lineoftext = "// Standard Prototypes" Then
PrintLine(2, Lineoftext) ' save this line
Lineoftext = LineInput(1) ' read the line
PrintLine(2, Lineoftext) ' save this line
Lineoftext = LineInput(1) ' read the line
PrintLine(2, Lineoftext) ' save this line
Lineoftext = "char *strupr(char *);" ' save declaration
End If
If Lineoftext = "// Runtime Functions" Then
PrintLine(2, Lineoftext) ' save this line
Lineoftext = LineInput(1) ' read the line
PrintLine(2, Lineoftext) ' save this line
Lineoftext = LineInput(1) ' read the line
PrintLine(2, Lineoftext) ' save this line
PrintLine(2, "char *strupr(char *string) {")
PrintLine(2, " int i, len;")
PrintLine(2, " len = strlen(string);")
PrintLine(2, " for (i = 0; i < len; i++) {")
PrintLine(2, " if (!isupper(string[i])) {")
PrintLine(2, " string[i] = toupper(string[i]);")
PrintLine(2, " }")
PrintLine(2, " }")
PrintLine(2, " return string;")
PrintLine(2, "}")
Lineoftext = vbCrLf ' add a space
End If
PrintLine(2, Lineoftext) ' save this line
End While
FileClose(1)
FileClose(2)
' if add more steps here, change the filecopy name below
' now copy this file back to the catalina directory and open it in the catalina text window
FileCopy("C:\Program Files\BCX\Bin\Cat5.c", "C:\Program Files\Catalina\Demos\NEW.C")
RichTextBox1.LoadFile("C:\Program Files\Catalina\Demos\NEW.C", RichTextBoxStreamType.PlainText)
CatalinaFile = "NEW.C" ' filename
should that be in the section System Variables? Or another section?
It sort of looks a bit lonely up there with the #includes.
You'll probably find more such - so stick it in it's own include file - e.g. dr_a_bcx.h and then instead add a line usch as #include "dr_a_bcx.h" (note the use of "" instead of <>). This will make it easier to add more such things later.
Making a lot of progress. Some Basic instructions work as-is. Some need a bit more work.
Huge arrays - 50000 integers = working
VAL and STR$ = working
ASC and CHR$ = working (needed to rewrite chr$ considerably)
strings - in addition to the ones above, now have lcase and concat
Block comments (even vb.net can't do that one!)
But I've got a little stuck with instr - searching for strings within strings.
Basic code
lineoftext1$="12345abc6789"
lineoftext2$="abc"
a=instr(lineoftext1$,lineoftext2$,3,0) ' instr search for characters. Last value is needed, use dummy 0 (matches case)
The line that catalina does not like is CharLowerA (addit - comes up also in HEX2DEC)
I suspect this is not ANSI C89. Description is CharLowerA is exported by user32.dll. Converts a character string or a single character to lowercase. If the operand is a character string, the function converts the characters in place.
How on earth does CharLowerA() know whether it's parameter is a pointer to a single character or a character string?
Is it so that it actually converts the string at the given pointer address to lower case and returns the first character as lower case as well. That seems dangerous as if the parameter points to a single character it may corrupt data following it if there is no following NULL.
In C we have such things as toupper() and tolower() which can be used to create the missing functions.
Yes, I know windows is a pain. Converting BCX to C89 is a worthy goal though.
I added another compile option to the catalina IDE. Now you can choose to compile with Catalina or with TinyC. Just hit F10 or F12. Compile/Run is instant for TinyC. And it is really useful to have a common language that works on a PC and works on the propeller.
(yes, ok, I have had to fudge the program to get TinyC to work - I have a little code that removes the code that changes the screen color t_color and t_setpos, and also there is no mathconst.h for tinyc).
It is also useful as part of the 'standardisation' process to test the code on two platforms.
I'm not actually sure what this subroutine is doing. Is it creating a table with values 0 to 255 but any ascii character that is upper case gets stored as lower case? ie tbl[65] contains 97
Heater suggested ctype.h and tolower()
but this uses integers, and the above code is using char
So is there any special casting that is needed to convert this line
That also fixed up Hex2Dec and Hex$, so now hex functions are working too.
One minor thing with hex is that DWORD is not defined, so I took a punt and used typedef to make it an unsigned long. Would this be the best choice for 32 bits?
Thanks for that. Sorry to keep asking all these questions. I guess it is worth pointing out that each question results in another instruction working, and I'm managing to solve about two out of three now without asking.
This one is for the string function, convert 10,65 to "AAAAAAAAAA
The line starting with "register" is creating all sorts of errors. (addit see below, it is the line above) But it compiles ok with TinyC. This is a strange one because that line looks almost identical to lines used many times in the code.
char *string (int count, int a)
{
if(count<1) return BCX_TmpStr(1);
register char *strtmp = BCX_TmpStr(count);
return (char*)memset(strtmp,a,count);
}
addit, I think the error actually is in the line above, if(count... because commenting out that line lets it compile
//if(count<1) return BCX_TmpStr(1);
come to think of it, why would you pass zero to this function? Anyway, is there a different way to write that line?
Addit - solved this one. Need to swap the order of the lines. Register it before any if statements.
I'm going to put a little note here to myself as this problem has come up with some other statements. need to register values before using them. So the order of the code changes. I hope I have done this right!
source
Addit - solved this one. Need to swap the order of the lines. Register it before any if statements.
Yes, this is a C89/C99 difference. LCC has been updated (by others) to be C99 compatible - when I get some time I'll look at doing this for Catalina - the differences are (for the most part) reasonably simple.
Tthe difference you just fell foul of is given in this document as no. 12. However, you should also note that some of the differences listed are already supported by Catalina (e.g. the C++ style comments, given in the document as no. 10).
When I get time I'll produce a "Catalina-specific" list.
I'm going to put a little note here to myself as this problem has come up with some other statements. need to register values before using them. So the order of the code changes. I hope I have done this right!
source
Dr_A,
All you have to do is separate the declaration of the variable from its usage, and put the declaration at the start of the block. For example:
Also, for future reference, the word register here is just a hint to the compiler that the variable should be put into a machine register if possible (rather than on the stack) - usually because it makes the code run faster. However, a compiler is free to ignore it if the request cannot be honoured.
I know you two have hashed this out, but... a coupla thoughts to share.
At a minimum, it's a "supervisor" kind of mode where there are meta-instructions. That's not quite the same as direct execution, though it does get executed directly by the COG, after being fetched. Seems to me, that's more than just running a program on a COG directly.
Just for arguments sake, if the LMM loop fetched (say) 8 instructions at a time instead of 1 and then executed them, would you say the same?
I think most people would regard that as being "native" execution using overlays.Or if 8 instructions is not enough, then how about I load 64 at a time? At what size of overlay does "non-native execution" turn into "native execution via overlays"? 128 instructions? 256?
The main reason it is not done this way is that it would actually be slower on the Prop I than the current LMM 1-instruction overlay (but maybe not on the Prop II, if my understanding of the instruction set is correct!). Plus of course any jumps in the code, and any "long immediate" operands would have to be handled slightly differently - but I have a mechanism (albeit slower) for handling that (clue: how do you get hold of the Propeller's internal PC if you need to know it?. And by the way, this is also a counter to Heater's argument about LMM requiring an additional and artifically maintained PC - but I'll hold fire on that one till he has the temerity to raise it again )
Making lots of progress now. The problem instructions seem to be strings. I have all the essentials working. The maths seem ok as are program loops and files. Lots of things working out of the box - even things that never were part of the earlier basics eg
print bin2dec("00000001") << 4
There are many instructions specific to a GUI on a PC so rather than trying to do those, next step might be to start with the Basic Stamp manual and see if I can get all those working.
Test program so far
' Big Basic for external memory on the Propeller using BCX Basic to C converter and Catalina
call WhiteOnBlue
dim a as integer
dim i as integer
for a=1 to 3
print "hello world";
print a
next a
$COMMENT
' file test copied from bcx examples - files work - commented out for speed
print "Opening file for output"
DIM MyFileHandle@ ' BCX Reserves @ for "C" FILE* data types
OPEN "new.txt" FOR OUTPUT AS FP1
MyFileHandle@ = FP1
FPRINT MyFileHandle@, "This is a test"
CLOSE FP1
print "Closing file"
$COMMENT
' ASC function
DIM Mystring$ as string * 80 ' 80 characters
DIM RetVal%
Mystring$="A"
print Mystring$
RetVal% = ASC(Mystring$)
PRINT RetVal%
'CHR$ function - opposite of ASC
a=65
Mystring$=chr$(a) ' declared in asc
print "Character should be A: ";Mystring$
'VAL function - converts string to double number. From the BCX help file
DIM StringNum$ as string * 20
DIM RetDub#
StringNum$="3.1415927"
RetDub#=VAL(StringNum$)
print RetDub#
'STR$ function - opposite of VAL. Converts number to string
DIM RetStr$ as string * 20
DIM DoubleNumber#
DoubleNumber# = 1.23456789
RetStr$ = STR$(DoubleNumber#)
print RetStr$
' Test some inline C code - pass a value in myarray, C changes it, print the return value
dim myarray[5] as integer ' this can be much bigger if you like, eg 50000
myarray[1]=100
print myarray[1]
call TestCCode
print myarray[1]
' test some string functions
dim lineoftext1$ as string * 80 ' strings must end in $ otherwise compiler doesn't copy properly
dim lineoftext2$ as string * 80
lineoftext1$="Hello World" ' string name is case sensitive
lineoftext2$=left$(lineoftext1$,4) ' left characters
print "Left$ test ";lineoftext2$
lineoftext2$=mid$(lineoftext1$,5,4) ' mid characters
print "Mid$ test ";lineoftext2$
lineoftext2$=ucase$(lineoftext1$) ' upper case
print "Upper case test ";lineoftext2$
lineoftext2$=right$(lineoftext1$,3) ' right characters
print "Right$ test ";lineoftext2$
lineoftext1$="Hello"
lineoftext2$="World"
concat(lineoftext1$,lineoftext2$) ' add two strings - same as + or & in vb.net
print "String concat test ";lineoftext1$
lineoftext1$="ABCDEFG"
lineoftext2$=lcase$(lineoftext1$) ' lower case
print "Lower case test ";lineoftext2$
a=1000
lineoftext1$=hex$(a) ' hex$ working
print lineoftext1$
dim retval% ' hex2dec = two errors, DWORD (which I think can be changed to unsigned long) and CharLowerA which instr also is unhappy about
retval%=hex2dec("0xFFFF") ' reverse of hex$, can use 0x or &H syntax or even FFFF
print "Hex2Dec test ";retval%
lineoftext1$="12345abc6789"
lineoftext2$="abc"
a=instr(lineoftext1$,lineoftext2$,3,0) ' instr search for characters. Last value is needed, use dummy 0 (matches case)
print "Instr test, string is at position ";a
a=255
lineoftext1$=bin$(a) ' test binary
lineoftext1$=lpad$(lineoftext1$,16,48) ' test adding leading zeros with lpad so is always 16 char long
print "Binary value is ";lineoftext1$ ' test binary to strings and back again
lineoftext1$="0000000001010101"
print "Binary string to decimal ";Bin2dec(lineoftext1$) ' binary
lineoftext1$=string$(10,65)
print "String function ";lineoftext1$' n characters of ascii value m
lineoftext1$=" trim test " ' trim off leading zeros, spaces etc
lineoftext1$=trim$(lineoftext1$)
print "Trim test:";lineoftext1$
' test a string array
dim stringarray[5] as string * 80 ' 80 characters
stringarray[1]="Hello"
stringarray[2]="World"
print stringarray[2]
' bitwise operators - there are many more of these but they all seem to work ok without code changes
a=1
a=a << 10
print "bitwise shift left";a
a=a >> 4
print "bitwise shift right";a
a=1
a=a and 0xFF
print "logical and";a
a=a or 0xFF
print "logical or";a
print "test starting with a binary string and shifting"; bin2dec("00000001") << 4
' test program control loops - FOR is already tested above
a=1
do
print a
a=a+1
loop until a=3
print "Do loop finished"
a=1
while a <3
print a
incr(a)' translates to a++ in C
wend
print "Wend loop finished"
a=5
select case a
case 1
print "1"
case > 1 and < 6
print "more than 1 and less than six"
case else
print "something else"
end select
' test functions
print addnumbers(5,6)
' test some maths with floating point numbers
dim number1 as double
number1=1.2345
print number1
print sin(number1)
print log(number1)
$CCODE
while(1); // loop instead of finishing
$CCODE
' and exitprocess does not work on the propeller. So don't use END for the moment
' subroutines and functions
function addnumbers(a as integer, b as integer)
dim returnvalue as integer
returnvalue = a + b
function=returnvalue
end function
sub TestCCode
$CCODE
// declare the variables:
int nNumber;
int *pPointer;
// now, give a value to them:
nNumber = 15;
pPointer = &nNumber;
// print out the value of nNumber:
printf("nNumber is equal to : %d\n", nNumber);
// now, alter nNumber through pPointer:
*pPointer = 25;
// prove that nNumber has changed as a result of the above
// by printing its value again:
printf("nNumber is equal to : %d\n", nNumber);
myarray[1]=110;
$CCODE
end sub
Sub WhiteOnBlue() ' white text on blue background
$CCODE
int i;
for (i=0;i<40;i++)
{
t_setpos(0,0,i); // move cursor to next line
t_color(0,0x08FC); // RRGGBBxx eg dark blue background 00001000 white text 11111100
}
$CCODE
End Sub
Sure. This is a one keypress exercise. This might be getting close for a release?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <ctype.h>
// *************************************************
// Typedef
// *************************************************
typedef unsigned char UCHAR;
typedef unsigned long DWORD;
// *************************************************
// System Variables
// *************************************************
static char *LowCase;
// *************************************************
// User Global Variables
// *************************************************
static int a;
static int i;
static int RetVal;
static double RetDub;
static double DoubleNumber;
static int retval;
static double number1;
static char Mystring[80];
static char StringNum[20];
static char RetStr[20];
static int myarray[5];
static char lineoftext1[80];
static char lineoftext2[80];
static char stringarray[5][80];
// *************************************************
// Standard Macros
// *************************************************
#define BAND &
#define BOR |
#define VAL(a)(double)atof(a)
// *************************************************
// Standard Prototypes
// *************************************************
char *strlwr(char *);
char *strupr(char *);
char* BCX_TmpStr(size_t);
char* lcase (char*);
char* ucase (char*);
char* mid (char*, int, int);
char* trim (char*);
char* left (char*,int);
char* right (char*,int);
char* lpad (char*,int,int);
char* string (int,int);
char* str (double);
char* hex (int);
char* Bin (int);
char* chr(int);
int instr(char*,char*,int,int);
char *MakeLCaseTbl(void);
char *_stristr_(char*,char*);
char *_strstr_(char*,char*);
int Bin2Dec (char*);
int Hex2Dec (char*);
// *************************************************
// User Prototypes
// *************************************************
int addnumbers (int, int);
void TestCCode (void);
void WhiteOnBlue (void);
// *************************************************
// User Global Initialized Arrays
// *************************************************
// *************************************************
// Main Program
// *************************************************
int main(int argc, char *argv[])
{
LowCase = (char*)calloc(257,1);
LowCase = MakeLCaseTbl();
WhiteOnBlue();
for(a=1; a<=3; a+=1)
{
printf("%s","hello world");
printf("% d\n",(int)a);
}
// ' file test copied from bcx examples - files work - commented out for speed
// print "Opening file for output"
// DIM MyFileHandle@ ' BCX Reserves @ for "C" FILE* data types
// OPEN "new.txt" FOR OUTPUT AS FP1
// MyFileHandle@ = FP1
// FPRINT MyFileHandle@, "This is a test"
// CLOSE FP1
// print "Closing file"
strcpy(Mystring,"A");
printf("%s\n",Mystring);
RetVal=(UCHAR)*(Mystring);
printf("% d\n",(int)RetVal);
a=65;
strcpy(Mystring,chr(a));
printf("%s%s\n","Character should be A: ",Mystring);
strcpy(StringNum,"3.1415927");
RetDub=VAL(StringNum);
printf("% .15G\n",(double)RetDub);
DoubleNumber=1.23456789;
strcpy(RetStr,str(DoubleNumber));
printf("%s\n",RetStr);
myarray[1]=100;
printf("% d\n",(int)myarray[1]);
TestCCode();
printf("% d\n",(int)myarray[1]);
strcpy(lineoftext1,"Hello World");
strcpy(lineoftext2,left(lineoftext1,4));
printf("%s%s\n","Left$ test ",lineoftext2);
strcpy(lineoftext2,mid(lineoftext1,5,4));
printf("%s%s\n","Mid$ test ",lineoftext2);
strcpy(lineoftext2,ucase(lineoftext1));
printf("%s%s\n","Upper case test ",lineoftext2);
strcpy(lineoftext2,right(lineoftext1,3));
printf("%s%s\n","Right$ test ",lineoftext2);
strcpy(lineoftext1,"Hello");
strcpy(lineoftext2,"World");
strcat(lineoftext1,lineoftext2);
printf("%s%s\n","String concat test ",lineoftext1);
strcpy(lineoftext1,"ABCDEFG");
strcpy(lineoftext2,lcase(lineoftext1));
printf("%s%s\n","Lower case test ",lineoftext2);
a=1000;
strcpy(lineoftext1,hex(a));
printf("%s\n",lineoftext1);
retval=Hex2Dec("0xFFFF");
printf("%s% d\n","Hex2Dec test ",(int)retval);
strcpy(lineoftext1,"12345abc6789");
strcpy(lineoftext2,"abc");
a=instr(lineoftext1,lineoftext2,3,0);
printf("%s% d\n","Instr test, string is at position ",(int)a);
a=255;
strcpy(lineoftext1,Bin(a));
strcpy(lineoftext1,lpad(lineoftext1,16,48));
printf("%s%s\n","Binary value is ",lineoftext1);
strcpy(lineoftext1,"0000000001010101");
printf("%s% d\n","Binary string to decimal ",(int)Bin2Dec(lineoftext1));
strcpy(lineoftext1,string(10,65));
printf("%s%s\n","String function ",lineoftext1);
strcpy(lineoftext1," trim test ");
strcpy(lineoftext1,trim(lineoftext1));
printf("%s%s\n","Trim test:",lineoftext1);
strcpy(stringarray[1],"Hello");
strcpy(stringarray[2],"World");
printf("%s\n",stringarray[2]);
a=1;
a=a<<10;
printf("%s% d\n","bitwise shift left",(int)a);
a=a>>4;
printf("%s% d\n","bitwise shift right",(int)a);
a=1;
a=a BAND 0xFF;
printf("%s% d\n","logical and",(int)a);
a=a BOR 0xFF;
printf("%s% d\n","logical or",(int)a);
printf("%s% d\n","test starting with a binary string and shifting",(int)Bin2Dec("00000001")<<4);
a=1;
for(;;)
{
printf("% d\n",(int)a);
a+=1;
if(a==3)
{
break;
}
}
printf("%s\n","Do loop finished");
a=1;
while(a<3)
{
printf("% d\n",(int)a);
(a)++;
}
printf("%s\n","Wend loop finished");
a=5;
for(;;)
{
if(a==1)
{
printf("%s\n","1");
break;
}
if(a>1&&a<6)
{
printf("%s\n","more than 1 and less than six");
break;
}
// case else
{
printf("%s\n","something else");
}
break;
}
printf("% d\n",(int)addnumbers(5,6));
number1=1.2345;
printf("% .15G\n",(double)number1);
printf("% .15G\n",(double)sin(number1));
printf("% .15G\n",(double)log(number1));
while(1); // loop instead of finishing
return 0; // End of main program
}
// *************************************************
// Runtime Functions
// *************************************************
char *strupr(char *string) {
int i, len;
len = strlen(string);
for (i = 0; i < len; i++) {
if (!isupper(string[i])) {
string[i] = toupper(string[i]);
}
}
return string;
}
char *strlwr(char *string) {
int i, len;
len = strlen(string);
for (i = 0; i < len; i++) {
if (!islower(string[i])) {
string[i] = tolower(string[i]);
}
}
return string;
}
char *BCX_TmpStr (size_t Bites)
{
static int StrCnt;
static char *StrFunc[2048];
StrCnt=(StrCnt + 1) & 2047;
if(StrFunc[StrCnt]) free (StrFunc[StrCnt]);
return StrFunc[StrCnt]=(char*)calloc(Bites+128,sizeof(char));
}
char *left (char *S, int length)
{
char *strtmp;
register int tmplen = strlen(S);
if(length<1) return BCX_TmpStr(1);
if(length<tmplen) tmplen=length;
strtmp = BCX_TmpStr(tmplen);
return (char*)memcpy(strtmp,S,tmplen);
}
char *right (char *S, int length)
{
int tmplen = strlen(S);
char *BCX_RetStr = BCX_TmpStr(tmplen);
tmplen -= length;
if (tmplen<0) tmplen = 0;
return strcpy(BCX_RetStr, &S[tmplen]);
}
char *lpad (char *a, int L, int c)
{
char *strtmp;
L=L-strlen(a);
if(L<1) return a;
strtmp = BCX_TmpStr(L);
memset(strtmp,c,L);
return strcat(strtmp,a);
}
char *mid (char *S, int start, int length)
{
char *strtmp;
register int tmplen = strlen(S);
if(start>tmplen||start<1) return BCX_TmpStr(1);
if (length<0 || length>(tmplen-start)+1)
length = (tmplen-start)+1;
strtmp = BCX_TmpStr(length);
return (char*)memcpy(strtmp,&S[start-1],length);
}
char *trim (char *S)
{
register int i = strlen(S);
char *strtmp=BCX_TmpStr(i);
while(*S==32 || *S==9 || *S==10 || *S==11 || *S==13)
S++;
while( i>0 && (S[i-1]==32 || S[i-1]==9 || S[i-1]==10 || S[i-1]==11 || S[i-1]==13))
i--;
strtmp=BCX_TmpStr(i);
return (char*)memcpy(strtmp,S,i);
}
char *ucase (char *S)
{
register char *strtmp = BCX_TmpStr(strlen(S));
return strupr(strcpy(strtmp,S));
}
char *lcase (char *S)
{
register char *strtmp = BCX_TmpStr(strlen(S));
return strlwr(strcpy(strtmp,S));
}
char *str (double d)
{
register char *strtmp = BCX_TmpStr(24);
sprintf(strtmp,"% .15G",d);
return strtmp;
}
char *hex (int a)
{
register char *strtmp = BCX_TmpStr(16);
sprintf(strtmp,"%X",a);
return strtmp;
}
char *string (int count, int a)
{
register char *strtmp = BCX_TmpStr(count);
if(count<1) return BCX_TmpStr(1);
return (char*)memset(strtmp,a,count);
}
char *chr (int a)
{
register char *strtmp = BCX_TmpStr(11);
strtmp[0] = a;
strtmp[1] = 0;
return strtmp;
}
char* Bin(int number)
{
char *strtmp = BCX_TmpStr(2048);
itoa(number,strtmp,2);
return strtmp;
}
int instr(char* mane,char* match,int offset,int sensflag)
{
register char *s;
if (!mane || !match || ! *match || offset>(int)strlen(mane)) return 0;
if (sensflag)
s = _stristr_(offset>0 ? mane+offset-1 : mane,match);
else
s = _strstr_(offset>0 ? mane+offset-1 : mane,match);
return s ? (int)(s-mane)+1 : 0;
}
char *MakeLCaseTbl (void) {
static char tbl[257];
int i;
for (i = 0; i < 256; i++) {
tbl[i] = tolower(i);
}
tbl[256] = 0;
return tbl;
}
char *_stristr_(char *String, char *Pattern)
{
int mi=-1;
while(Pattern[++mi])
{
if(String[mi]==0) return 0;
if(LowCase[(unsigned char)String[mi]]!=LowCase[(unsigned char)Pattern[mi]])
{ String++; mi=-1; }
}
return String;
}
char *_strstr_(char *String, char *Pattern)
{
int mi=-1;
while(Pattern[++mi])
{
if(String[mi]==0) return 0;
if(String[mi]!=Pattern[mi])
{ String++; mi=-1; }
}
return String;
}
int Bin2Dec (char *cptr)
{
register int i, j = 0;
while(cptr && *cptr && strchr("01", *cptr))
{
i = *cptr++ - '0';
j <<= 1;
j |= (i & 0x01);
}
return(j);
}
int Hex2Dec (char *szInput)
{
char ch;
char *dwLen = szInput+strlen(szInput);
DWORD dwOut = 0;
while(*szInput)
{
ch = LowCase[(unsigned char)*szInput++];
if((ch >= 'a' && ch <= 'f') || (ch >= '0' && ch <= '9'))
dwOut |=((int)ch - (ch>'9' ? 'a'-10 : '0')) << ((dwLen - szInput) << 2);
}
return dwOut;
}
// ************************************
// User Subs and Functions
// ************************************
int addnumbers (int a, int b)
{
static int returnvalue;
memset(&returnvalue,0,sizeof(returnvalue));
returnvalue=a+b;
return returnvalue;
}
void TestCCode (void)
{
// declare the variables:
int nNumber;
int *pPointer;
// now, give a value to them:
nNumber = 15;
pPointer = &nNumber;
// print out the value of nNumber:
printf("nNumber is equal to : %d\n", nNumber);
// now, alter nNumber through pPointer:
*pPointer = 25;
// prove that nNumber has changed as a result of the above
// by printing its value again:
printf("nNumber is equal to : %d\n", nNumber);
myarray[1]=110;
}
void WhiteOnBlue (void)
{
int i;
for (i=0;i<40;i++)
{
t_setpos(0,0,i); // move cursor to next line
t_color(0,0x08FC); // RRGGBBxx eg dark blue background 00001000 white text 11111100
}
}
The secret is to add little functions to change the output from BCX. This is an example of how one works. I'd be wondering if maybe this could be translated from vb.net into BCX. Then BCX could translate itself? (not so silly, since the source of BCX is written in Basic and it can translate itself).
Function Trim_Replace(ByVal Lineoftext As String, ByVal SaveFlag As Boolean)
' swap around the declarations so they are all at the start, eg register. TinyC does not mind but Catalina does.
'char *trim (char *S)
'{
' while(*S==32 || *S==9 || *S==10 || *S==11 || *S==13)
' S++;
'register int i = strlen(S);
'while( i>0 && (S[i-1]==32 || S[i-1]==9 || S[i-1]==10
'|| S[i-1]==11 || S[i-1]==13))
'i--;
'char *strtmp=BCX_TmpStr(i);
'return (char*)memcpy(strtmp,S,i);
'}
If Strings.Left(Lineoftext, 20) = "char *trim (char *S)" Then
For i = 1 To 10 ' replace function
Lineoftext = LineInput(1) ' read in lines and discard
Next
PrintLine(2, "char *trim (char *S)")
PrintLine(2, "{")
PrintLine(2, " register int i = strlen(S);")
PrintLine(2, " char *strtmp=BCX_TmpStr(i);")
PrintLine(2, " while(*S==32 || *S==9 || *S==10 || *S==11 || *S==13)")
PrintLine(2, " S++;")
PrintLine(2, " while( i>0 && (S[i-1]==32 || S[i-1]==9 || S[i-1]==10 || S[i-1]==11 || S[i-1]==13))")
PrintLine(2, " i--;")
PrintLine(2, " strtmp=BCX_TmpStr(i);")
PrintLine(2, " return (char*)memcpy(strtmp,S,i);")
PrintLine(2, "}")
SaveFlag = False
End If
Return SaveFlag
End Function
Yes I would say the same. IMHO, the differentiator for me is whether or not there are meta-tasks, and where the intent of the program is embodied.
With LMM, whether it's one instruction, or a few, or 8, whatever, the center of attention isn't the kernel running in the COG. That is a meta-task, necessary and contributory to the primary task, embodied in the LMM program. That's virtualization, or at a minimum a model similar to a micro-code one where there is some program-ability, used to facilitate execution, and or provide high speed services to the program being executed. A supervisor kernel facilitates the execution of the program.
We've seen some programs that are a mix of PASM and LMM, where the main intent is embodied in the PASM, with the meta-task being to fetch different parts of the program as needed. I would characterize that differently, as a overlay.
Subtle, but IMHO, significant.
Edit:
One other distinction would be whether or not the meta-program is general purpose or not. Using the overlay technique is specialized, in that the workflow to realize it is consistent, but the actual implementation is case by case, depending on the program intent necessary at the time.
When that is general purpose, it then is enabling, not primary, which speaks again to supervisory code, or modes, and or the core of virtual machines.
For those with vb.net, attached is the code. You will also need BCX installed in the default c:\program files\bcx and it helps to have TinyC installed, also in the default c:\program files\tcc
One could certainly argue the merits of taking the post BCX conversion part and turning that into a standalone .exe so that the linux people can use this. Heater found Qt which can run C on multiple platforms. I wonder if there is an equivalent program for Basic programmers?
It would seem a beta release may in order! Although I do think your idea of trying to do a fairly complete emulation of some variant of BASIC (like PBASIC) would make a very good first release.
Comments
Hi Ross, re "I use gcc on both Windows and Linux."
I think I'm missing something obvious with this one. This site http://gcc.gnu.org/releases.html leads you to this page http://gcc.gnu.org/gcc-4.5/ which leads you to this page http://gcc.gnu.org/svn.html and, you know, I just wanted the files!!
Back to heater, I think what we have with Catalina is this amazing piece of code that is being greatly under utilised at the moment. BDSC is great, but it exists in CP/M so it is limited by the 64k memory limit. Catalina breaks out of this limit and can run free with as much ram as you want to throw at it.
So my generic idea is to somehow leverage the power of Catalina into other languages. Ross has stuck with ANSI standards and this means at least we do have a standard.
Qt is great but even a "hello world" seems to have one non ANSI line of code in it. Maybe it will end up the only one but it is mildly concerning in terms of standards. And look, I can't resist, I can feel a rant coming on, here it comes... /rant/ why, oh why, with a simple .exe can't they wrap up the .dll as well? No-one else ever is going to use that .dll. The .exe is not the compiled program. It is half the compiled program. How hard can it be to produce a single executable file?? /end rant/
So, back to the real world, BCX produces some somewhat hybrid code, but Ross has already shown that it can be converted to ANSI C. In particular, BCX can include raw C code in a Basic program, so it can be possible to write simple C functions in standard ANSI C to replace non ANSI C produced by the converter.
Where this could take us is very flexible code that can run on the Propeller, on a PC and on Linux. And Zog? I think that is a worthy goal worth pursuing.
So what I want to do is write a BCX to ANSI C converter, and I want to write that in ANSI C. Which I might choose to write in Basic first!
So my next little quest is for a simple C compiler that can run the same code Catalina is running.
Tiny C can produce a complete self contained .exe from this
But can it do the same for Linux?
Dumb question here, but can Catalina produce code that can run on a PC?
If not, what I would like is a simple C compiler that can take a program and can run on multiple platforms. If we stick to ANSI C, Catalina is that program for the propeller. Maybe GCC or Qt can do it for the PC. Not sure about linux. TinyC works for me on a PC but what about other OS'?
I hope that all makes sense!
Don't worry I'm only debating the LMM issue for fun.
Now to business...
You really don't want to be getting your GCC from gnu.org. They have the source for it...but then you would need to compile it into a working compiler...but then you would need a working GCC to compile it... but then....
Normally Linux users get their GCC along with the OS.
You already have a perfectly good C89 compliant GCC C compiler on your machine. It's in the Qt IDE. Just write C89 standard code into there and it will compile and run just fine.
Have a look at "compile output" (look for the "build issues" drop down menu. I'm sure you will see the QT IDE is running a mingw version of GCC. You will be able to see it's path there. Then you can use it from the command line as a regular C compiler. (No funny command line switches added by the QT IDE) and no C++ or Qt libs involved.
Otherwise there is:
mingw http://www.mingw.org/
cygwin http://www.cygwin.com/
BloodShed http://www.bloodshed.net/download.html
Don't get me wrong I have the highest respect for Ross and Catalina, it is an amazing piece of work that I hope to see more widely adopted.
BDSC is, well, just for fun.
Using Catalina to enable other language support is an excellent idea. Ross already has Lua for example. BASIC would be welcome by many. A standards compliant C for the basis of these things is essential.
There is nothing mildly concerning about standards with Qt. It's just C++ not C.
As for dll's. A valid rant. But consider on my Linux box those shared libs are actually used by my entire GUI desktop and a bunch of apps. We will find a way to build a statically linked self contained Qt executable for Windows.
Zog thinks this is an excellent idea as well. By the way, that's what C is all about and why everyone and his dog want's C on the Prop.
Catalina is actually LCC plus a back end code generator for the Propeller. So what you are really asking for is LCC to produce code for x86 Windows. See here http://www.cs.virginia.edu/~lcc-win32/ or http://www.programmersheaven.com/download/31851/download.aspx or wherever.
I wont respond to each point in your emails individually (don't you guys ever sleep?). But here are some points, in no particular order ....
- Heater and I will no doubt resume the LMM argument periodocally. Neither of us really expects to win - it's the argument that counts. Winning is less important than scoring a good point here and there

- I use the MinGW (and MSYS) distribution of gcc for Windows. Some details are given in the Catalina reference manual. On Linux (as heater points out) gcc is nearly always included - or is downloadable as an easily installable package. Don't try and compile it from scratch!
- There's no need to port Catalina to Windows (or Linux) - just use LCC instead. If you need a set of ANSI C libraries, you can use the Amsterdam Compiler Kit C libraries (these are what the Catalina libraries are based on). Or you can use LCC-Win32 (this is a compiler based on LCC - it is free for non-commercial use but not open source).
- I always intended Catalina to be used as the basis for other languages for the Propeller - I just never seem to get time to do any work on them! You can either translate them to C and then use Catalina to compile them (as Dr_A is doing, or Lua or Pascal or Dumbo Basic does) or else compile them to PASM and then just make use of the Catalina targets, LMM kernel and other support tools - i.e. loaders, libraries etc. This latter technique has not yet been exploted by anyone (including me!) but is likely to give much faster results than using C as an intermediate language.
- Thanks for the kind words about Catalina.
Ross.I would like to repackage Catalina with pre-compiled "armel" binaries for the Z2. Do I have your permission?
Hi Martin,
Thanks for asking - by all means include it. If you are going to include release 2.9, please also include the latest C3 patch, which also adds debugger support for all platforms. I have just added a copy of this patch to the Catalina Source Forge site (along with the 2.9 distribution files).
For future reference (and for others who may want to do the same) you don't really need to ask my permission. Since Catalina is open source, you just need to comply with the various license terms.
For the technically minded, these are the LGPL, GPL & MIT licenses, plus the two special ones for LCC and the Amsterdam Compiler Kit C libraries - but all these licenses permit redistribution provided their license conditions are preserved intact in the redistribution.
Ross.
Not sure if there is a Basic program that runs on both??
In any case, one thing that is nice about converting the output of BCX into C89 is that it compiles with TinyC. So it is getting to the stage of being possible to write code in Basic and translate it to something that will run on the propeller and on multiple platforms.
I put in some syntax highlighting.
This isn't finished and obviously every instruction will need to be tested, but the code below does test out a few key concepts - eg replacing lines with new lines, inserting new code, searching for code and replacing with other code that is bigger or smaller.
As an aside, see the second screenshot, should that be in the section System Variables? Or another section?
It sort of looks a bit lonely up there with the #includes.
vb.net code below:
You'll probably find more such - so stick it in it's own include file - e.g. dr_a_bcx.h and then instead add a line usch as #include "dr_a_bcx.h" (note the use of "" instead of <>). This will make it easier to add more such things later.
Ross.
Making a lot of progress. Some Basic instructions work as-is. Some need a bit more work.
Huge arrays - 50000 integers = working
VAL and STR$ = working
ASC and CHR$ = working (needed to rewrite chr$ considerably)
strings - in addition to the ones above, now have lcase and concat
Block comments (even vb.net can't do that one!)
But I've got a little stuck with instr - searching for strings within strings.
Basic code
which outputs a whole lot of C
The line that catalina does not like is CharLowerA (addit - comes up also in HEX2DEC)
I suspect this is not ANSI C89. Description is CharLowerA is exported by user32.dll. Converts a character string or a single character to lowercase. If the operand is a character string, the function converts the characters in place.
Is there something similar in C89?
Is it so that it actually converts the string at the given pointer address to lower case and returns the first character as lower case as well. That seems dangerous as if the parameter points to a single character it may corrupt data following it if there is no following NULL.
In C we have such things as toupper() and tolower() which can be used to create the missing functions.
http://pubs.opengroup.org/onlinepubs/009695399/functions/toupper.html
Answer to my question is:
Which means that if you give it a string at an address less than $1FFFF then it thinks you are passing it a single character and everything fails.
This seems to be a quite likely scenario in your application on the Prop.
Isn't Windows wonderful?
Yes, Windows is a gem, isn't it?. Don't you just love this bit (taken verbatim from Heater's reference above):
I'm definitely writing my next nuclear reactor controller in Windows!
Ross.
I added another compile option to the catalina IDE. Now you can choose to compile with Catalina or with TinyC. Just hit F10 or F12. Compile/Run is instant for TinyC. And it is really useful to have a common language that works on a PC and works on the propeller.
(yes, ok, I have had to fudge the program to get TinyC to work - I have a little code that removes the code that changes the screen color t_color and t_setpos, and also there is no mathconst.h for tinyc).
It is also useful as part of the 'standardisation' process to test the code on two platforms.
So - back to the problem
I'm not actually sure what this subroutine is doing. Is it creating a table with values 0 to 255 but any ascii character that is upper case gets stored as lower case? ie tbl[65] contains 97
Heater suggested ctype.h and tolower()
but this uses integers, and the above code is using char
So is there any special casting that is needed to convert this line
to something that uses tolower()
Try this: Ross.
One minor thing with hex is that DWORD is not defined, so I took a punt and used typedef to make it an unsigned long. Would this be the best choice for 32 bits?
print hex2dec("0xFFFFFFFF") prints -1
0xFFFF prints 65535
I'm used to 16 bits so to my eyes, FFFF is -1. Maybe someone used to programming a 64 bit machine would consider FFFFFFFF to be 4294967295.
It probably doesn't matter in terms of the debate, but from my point of view I want to make sure than my choice for DWORD is correct. Your thoughts?
Yes strtol() is available in Catalina.
As to DWORD - I would just use unsigned - see http://msdn.microsoft.com/en-us/library/cc230318%28PROT.10%29.aspx
Ross.
This one is for the string function, convert 10,65 to "AAAAAAAAAA
The line starting with "register" is creating all sorts of errors. (addit see below, it is the line above) But it compiles ok with TinyC. This is a strange one because that line looks almost identical to lines used many times in the code.
addit, I think the error actually is in the line above, if(count... because commenting out that line lets it compile
come to think of it, why would you pass zero to this function? Anyway, is there a different way to write that line?
Addit - solved this one. Need to swap the order of the lines. Register it before any if statements.
I'm going to put a little note here to myself as this problem has come up with some other statements. need to register values before using them. So the order of the code changes. I hope I have done this right!
source
new code
Yes, this is a C89/C99 difference. LCC has been updated (by others) to be C99 compatible - when I get some time I'll look at doing this for Catalina - the differences are (for the most part) reasonably simple.
For future reference, here is a quick summary of the differences between C89 and C99: http://home.datacomm.ch/t_wolf/tw/c/c9x_changes.html.
Tthe difference you just fell foul of is given in this document as no. 12. However, you should also note that some of the differences listed are already supported by Catalina (e.g. the C++ style comments, given in the document as no. 10).
When I get time I'll produce a "Catalina-specific" list.
Ross.
Dr_A,
All you have to do is separate the declaration of the variable from its usage, and put the declaration at the start of the block. For example: Also, for future reference, the word register here is just a hint to the compiler that the variable should be put into a machine register if possible (rather than on the stack) - usually because it makes the code run faster. However, a compiler is free to ignore it if the request cannot be honoured.
Ross.
I know you two have hashed this out, but... a coupla thoughts to share.
At a minimum, it's a "supervisor" kind of mode where there are meta-instructions. That's not quite the same as direct execution, though it does get executed directly by the COG, after being fetched. Seems to me, that's more than just running a program on a COG directly.
Just for arguments sake, if the LMM loop fetched (say) 8 instructions at a time instead of 1 and then executed them, would you say the same?
I think most people would regard that as being "native" execution using overlays.Or if 8 instructions is not enough, then how about I load 64 at a time? At what size of overlay does "non-native execution" turn into "native execution via overlays"? 128 instructions? 256?
The main reason it is not done this way is that it would actually be slower on the Prop I than the current LMM 1-instruction overlay (but maybe not on the Prop II, if my understanding of the instruction set is correct!). Plus of course any jumps in the code, and any "long immediate" operands would have to be handled slightly differently - but I have a mechanism (albeit slower) for handling that (clue: how do you get hold of the Propeller's internal PC if you need to know it?. And by the way, this is also a counter to Heater's argument about LMM requiring an additional and artifically maintained PC - but I'll hold fire on that one till he has the temerity to raise it again
Ross.
There are many instructions specific to a GUI on a PC so rather than trying to do those, next step might be to start with the Basic Stamp manual and see if I can get all those working.
Test program so far
That's very impressive!
Can you post the translated C version of the same code (you may need to zip it up)?
Ross.
The secret is to add little functions to change the output from BCX. This is an example of how one works. I'd be wondering if maybe this could be translated from vb.net into BCX. Then BCX could translate itself? (not so silly, since the source of BCX is written in Basic and it can translate itself).
With LMM, whether it's one instruction, or a few, or 8, whatever, the center of attention isn't the kernel running in the COG. That is a meta-task, necessary and contributory to the primary task, embodied in the LMM program. That's virtualization, or at a minimum a model similar to a micro-code one where there is some program-ability, used to facilitate execution, and or provide high speed services to the program being executed. A supervisor kernel facilitates the execution of the program.
We've seen some programs that are a mix of PASM and LMM, where the main intent is embodied in the PASM, with the meta-task being to fetch different parts of the program as needed. I would characterize that differently, as a overlay.
Subtle, but IMHO, significant.
Edit:
One other distinction would be whether or not the meta-program is general purpose or not. Using the overlay technique is specialized, in that the workflow to realize it is consistent, but the actual implementation is case by case, depending on the program intent necessary at the time.
When that is general purpose, it then is enabling, not primary, which speaks again to supervisory code, or modes, and or the core of virtual machines.
One could certainly argue the merits of taking the post BCX conversion part and turning that into a standalone .exe so that the linux people can use this. Heater found Qt which can run C on multiple platforms. I wonder if there is an equivalent program for Basic programmers?
It would seem a beta release may in order! Although I do think your idea of trying to do a fairly complete emulation of some variant of BASIC (like PBASIC) would make a very good first release.
Ross.