AllBASIC

BASIC Developer & Support Resources => Translators => C BASIC => Topic started by: John on May 18, 2014, 01:39:15 PM

Title: C BASIC Runtime
Post by: John on May 18, 2014, 01:39:15 PM
I have begun with forking the BaCon runtime library to C BASIC. If you are interested in a translatorless C BASIC environment based on ANSI C and the compiler's preprocessor facilities, the code repository is on the Bitbucket (https://bitbucket.org/ScriptBasic/c-basic) site. (CBRT source folder) Comments, code and commitment are always appreciated.

Title: Re: C BASIC Runtime
Post by: John on May 19, 2014, 10:30:00 AM
Once I get Peter's BaCon code working in C BASIC, I will more than likely replace his string/memory manager with Peter Vehas's MyAlloc for thread safe memory/garbage collection. BaCon seems to be reallocation happy in its design.  :-\
Title: Re: C BASIC Runtime
Post by: John on May 19, 2014, 06:00:04 PM
This is the BaCon CHOP$() runtime function.

Quote
CHOP$(x$[, y$[, z]])

Type: function

Returns a string defined in x$ where on both sides <CR>, <NL>, <TAB> and <SPACE> have been removed. If other characters need to be chopped then these can be specified in the optional y$. The optional parameter z defines where the chopping must take place: 0 means on both sides, 1 means chop at the left and 2 means chop at the right. Examples:

PRINT CHOP$("bacon", "bn")
PRINT CHOP$(" hello world ", " ", 2)

Here is the BaCon code for it.

Code: [Select]
#include "bacon.bac.generic.h"
char* __b2c__chop(char *__b2c__src, ...){char *__b2c__tmp, *__b2c__str; long __b2c__i, __b2c__l, __b2c__loc = 0; va_list __b2c__ap; if(__b2c__src == NULL || strlen(__b2c__src) == 0) return(__b2c__src);
va_start (__b2c__ap, __b2c__src); __b2c__str = va_arg (__b2c__ap, char*); if(__b2c__str == 0) __b2c__str = (char*)__b2c__chop_default; else __b2c__loc = va_arg (__b2c__ap, int); va_end (__b2c__ap); __b2c__l = strlen(__b2c__str);
if(__b2c__loc == 0 || __b2c__loc == 1) {while (*__b2c__src != '\0') {for(__b2c__i = 0; __b2c__i < __b2c__l; __b2c__i++) {if (*__b2c__src == *(__b2c__str+__b2c__i)) {__b2c__src++; break; } }
if(__b2c__i == __b2c__l) break;} if (*__b2c__src == '\0') return("");} __b2c__tmp = __b2c__src + strlen(__b2c__src) - 1;
if(__b2c__loc == 0 || __b2c__loc == 2) {while (__b2c__tmp >= __b2c__src && *__b2c__tmp != '\0') {for(__b2c__i = 0; __b2c__i < __b2c__l; __b2c__i++) {if (*__b2c__tmp == *(__b2c__str+__b2c__i))
{__b2c__tmp--; break; } } if(__b2c__i == __b2c__l) break;} } __b2c__sbuffer_ptr++; if(__b2c__sbuffer_ptr >= 256) __b2c__sbuffer_ptr=0;
__b2c__sbuffer[__b2c__sbuffer_ptr] = (char*)__sbuf_realloc(__b2c__sbuffer[__b2c__sbuffer_ptr], (strlen(__b2c__src)+1)*sizeof(char));
for(__b2c__i = 0; __b2c__i <= __b2c__tmp - __b2c__src; __b2c__i++) __b2c__sbuffer[__b2c__sbuffer_ptr][__b2c__i]=__b2c__src[__b2c__i];
__b2c__sbuffer[__b2c__sbuffer_ptr][__b2c__i] = '\0'; return (__b2c__sbuffer[__b2c__sbuffer_ptr]);}

Here is the C BASIC version of it. We could almost make a code challenge out what the above code does.  :)

Code: [Select]
FUNCTION char PTR cbrt_chop(char PTR cbrt_src, ...)
BEGIN_FUNCTION
  DIM AS char PTR cbrt_tmp, PTR cbrt_str;
  DIM AS long cbrt_i, cbrt_l, cbrt_loc = 0;
  DIM AS va_list cbrt_ap;
  IF (cbrt_src EQ NULL OR strlen(cbrt_src) EQ 0) THEN_DO RETURN_FUNCTION(cbrt_src);
  va_start(cbrt_ap, cbrt_src);
  cbrt_str = va_arg(cbrt_ap, char PTR);
  IF (cbrt_str EQ 0) THEN
    cbrt_str = (char PTR)cbrt_chop_default;
  ELSE
    cbrt_loc = va_arg(cbrt_ap, int);
  END_IF
  va_end(cbrt_ap);
  cbrt_l = strlen(cbrt_str);
  IF (cbrt_loc EQ 0 OR cbrt_loc EQ 1) THEN
    DEF_WHILE (PTR cbrt_src NE '\0')
    BEGIN_WHILE
      DEF_FOR (cbrt_i = 0 TO cbrt_i < cbrt_l STEP INCR cbrt_i)
      BEGIN_FOR
        IF (PTR cbrt_src EQ PTR(cbrt_str + cbrt_i)) THEN
          INCR cbrt_src;
          EXIT_FOR
        END_IF
      NEXT
      IF (cbrt_i EQ cbrt_l) THEN_DO EXIT_WHILE
    WEND
    IF (PTR cbrt_src NE '\0') THEN_DO RETURN_FUNCTION("");
  END_IF
  cbrt_tmp = cbrt_src + strlen(cbrt_src) - 1;
  IF (cbrt_loc EQ 0 OR cbrt_loc EQ 2) THEN
    DEF_WHILE (cbrt_tmp >= cbrt_src AND PTR cbrt_tmp NE '\0')
    BEGIN_WHILE
      DEF_FOR (cbrt_i = 0 TO cbrt_i < cbrt_l STEP INCR cbrt_i)
      BEGIN_FOR
        IF (PTR cbrt_tmp EQ PTR(cbrt_str+cbrt_i)) THEN
          DECR cbrt_tmp;
          EXIT_FOR
        END_IF
      NEXT
      IF (cbrt_i EQ cbrt_l) THEN_DO EXIT_WHILE
    WEND
  END_IF
  INCR cbrt_sbuffer_ptr;
  IF (cbrt_sbuffer_ptr >= 256) THEN_DO cbrt_sbuffer_ptr = 0;
  cbrt_sbuffer[cbrt_sbuffer_ptr] = (char PTR)__sbuf_realloc(cbrt_sbuffer[cbrt_sbuffer_ptr], (strlen(cbrt_src) + 1) * sizeof(char));
  DEF_FOR (cbrt_i = 0 TO cbrt_i <= cbrt_tmp - cbrt_src STEP INCR cbrt_i)
  BEGIN_FOR
    cbrt_sbuffer[cbrt_sbuffer_ptr][cbrt_i] = cbrt_src[cbrt_i];
  NEXT
  cbrt_sbuffer[cbrt_sbuffer_ptr][cbrt_i] = '\0';
  RETURN_FUNCTION(cbrt_sbuffer[cbrt_sbuffer_ptr]);
END_FUNCTION

Here is the C BASIC version expanded back to standard C source.

Code: [Select]
char * cbrt_chop(char * cbrt_src, ...)
{
  char * cbrt_tmp, * cbrt_str;
  long cbrt_i, cbrt_l, cbrt_loc = 0;
  va_list cbrt_ap;
  if (cbrt_src == NULL || strlen(cbrt_src) == 0) return(cbrt_src);
  va_start(cbrt_ap, cbrt_src);
  cbrt_str = va_arg(cbrt_ap, char *);
  if (cbrt_str == 0) {
    cbrt_str = (char *)cbrt_chop_default;
  } else {
    cbrt_loc = va_arg(cbrt_ap, int);
  }
  va_end(cbrt_ap);
  cbrt_l = strlen(cbrt_str);
  if (cbrt_loc == 0 || cbrt_loc == 1) {
    while (* cbrt_src != '\0')
    {
      for (cbrt_i = 0 ; cbrt_i < cbrt_l ; ++ cbrt_i)
      {
        if (* cbrt_src == *(cbrt_str + cbrt_i)) {
          ++ cbrt_src;
          break;
        }
      }
      if (cbrt_i == cbrt_l) break;
    }
    if (* cbrt_src != '\0') return("");
  }
  cbrt_tmp = cbrt_src + strlen(cbrt_src) - 1;
  if (cbrt_loc == 0 || cbrt_loc == 2) {
    while (cbrt_tmp >= cbrt_src && * cbrt_tmp != '\0')
    {
      for (cbrt_i = 0 ; cbrt_i < cbrt_l ; ++ cbrt_i)
      {
        if (* cbrt_tmp == *(cbrt_str+cbrt_i)) {
          -- cbrt_tmp;
          break;
        }
      }
      if (cbrt_i == cbrt_l) break;
    }
  }
  ++ cbrt_sbuffer_ptr;
  if (cbrt_sbuffer_ptr >= 256) cbrt_sbuffer_ptr = 0;
  cbrt_sbuffer[cbrt_sbuffer_ptr] = (char *)__sbuf_realloc(cbrt_sbuffer[cbrt_sbuffer_ptr], (strlen(cbrt_src) + 1) * sizeof(char));
  for (cbrt_i = 0 ; cbrt_i <= cbrt_tmp - cbrt_src ; ++ cbrt_i)
  {
    cbrt_sbuffer[cbrt_sbuffer_ptr][cbrt_i] = cbrt_src[cbrt_i];
  }
  cbrt_sbuffer[cbrt_sbuffer_ptr][cbrt_i] = '\0';
  return(cbrt_sbuffer[cbrt_sbuffer_ptr]);
}

Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 19, 2014, 09:09:00 PM
Once I get Peter's BaCon code working in C BASIC, I will more than likely replace his string/memory manager with Peter Vehas's MyAlloc for thread safe memory/garbage collection. BaCon seems to be reallocation happy in its design.

I don't know if BaCon is thread safe but if not, then just replacing the all-purpose malloc/realloc with a pool allocator is not necessarily going to make BaCon thread safe. You will have to get rid of almost all global variables and replace them with function arguments where possible, or protect them with semaphores/mutexes/whatever to preclude inter-thread memory read/write conflicts.

At any rate, this is going to be a grueling experience debugging and polishing your fork, thread safe or otherwise. ;)
Title: Re: C BASIC Runtime
Post by: John on May 19, 2014, 09:21:58 PM
Quote from: Peter Verhas
MyAlloc memory management module.

The MyAlloc memory management module is to help the programmer to avoid crating memory leaking applications. When allocating dynamic memory via malloc you have to release it using free. Old programs do not care too much about freeing the memory as the task was done by the operating system, whenever the process ended. Nowadays single process, multithread applications should release memory.

Using the package MyAlloc you first create a memory segment. A memory segment is a logical entity. Whenever you allocate a new piece of memory you have to specify what memory segment you want to use for it. MyAlloc does not preallocate memory, just keeps track of the memory pieces that were allocated for the segment. Whenever you want to get rid of all memories allocated for a segment you can release them all with a single function call without calling free for each malloced memory piece.

You can release memory segments, merge them together, release memory pieces allocated to a segment and so on.

The module is GNU LGPL and is part of the ScriptBasic interpreter package.

The Script BASIC sbhttpd multi-threaded application server that runs as a service is a good example of MyAlloc in threaded use.

Quote from: Mike
At any rate, this is going to be a grueling experience debugging and polishing your fork, thread safe or otherwise.

Porting BaCon to C BASIC now that Peter broke up the runtime into separate objects makes this a rather easy task. C BASIC already works in concept and just needs more of a runtime than C and it's standard libraries provide. I have already made C BASIC a standard in Script BASIC's extension module API header file.

Script BASIC first forks a child process which the script runs independently in. Using the MT extension module, thread child process can share a common variable / session pool. Script BASIC was designed from the ground up to be a thread safe scripting language API.

Quote from: Peter Verhas
MT extension module

You can use this module in multi threaded environment. In this case the module depend on the module thread.c which contains the thread and mutex interface functions that call the operating system thread and mutex functions on UNIX and on Windows NT.

In single thread environment there is no need to use the locking mechanism. To get a single-thread version either you can edit this file (myalloc.c) or compile is using the option -DMTHREAD=0 The default compilation is multi threaded.

Multi thread implementation has two levels. One is that the subroutines implemented in this module call the appropriate locking functions to ensure that no two concurrent threads access and modify the same data at a time and thus assure that the data of the module is correct. The other level is that you can tell the module that the underlying memory allocation and deallocation modules are mot thread safe. There are global variables implementing global mutexes that are locked and unlocked if you use the module that way. This can be useful in some environment where malloc and free are not thread safe.


(http://files.allbasic.info/ScriptBasic/sbmt.png)
Title: Re: C BASIC Runtime
Post by: John on May 19, 2014, 10:54:55 PM
This is a C BASIC IUP button example showing how button events are captured, adding an image (from code) that toggles with the button state. The second image shows the button disabled. The big useless button state is printed to the console. (left/center[wheel]/right) Notice that the title bar system buttons are also disable (hidden) along with the ability to resize the window.

(http://files.allbasic.info/C_BASIC/button_enabled.png)    (http://files.allbasic.info/C_BASIC/button_disabled.png)

Code: [Select]
// C BASIC - IUP Button
// gcc button.c -I/usr/include/iup -liup -o button

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iup.h>
#include "cbasic.h"

DIM AS static unsigned char pixmap_release[] =
{
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2,
       1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2,
       1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2,
       1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
       2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
};

DIM AS static unsigned char pixmap_press[] =
{
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,4,4,3,3,3,3,3,2,2,
       1,1,3,3,3,3,4,4,4,4,3,3,3,3,2,2,
       1,1,3,3,3,3,4,4,4,4,3,3,3,3,2,2,
       1,1,3,3,3,3,3,4,4,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
       2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
};

DIM AS static unsigned char pixmap_inactive[] =
{
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2,
       1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2,
       1,1,3,3,3,3,3,4,4,4,4,3,3,3,2,2,
       1,1,3,3,3,3,3,3,4,4,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,1,3,3,3,3,3,3,3,3,3,3,3,3,2,2,
       1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
       2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
};

CB_FUNCTION btn_on_off_cb(Ihandle PTR self)
BEGIN_FUNCTION
  DIM AS Ihandle PTR btn_image;
  btn_image = IupGetHandle("btn_image");
  IF (NOT strcmp(IupGetAttribute(btn_image, "ACTIVE"), "YES")) THEN
    IupSetAttribute(btn_image, "ACTIVE","NO");
  ELSE
    IupSetAttribute(btn_image, "ACTIVE", "YES");
  END_IF
  RETURN_FUNCTION(IUP_DEFAULT);
END_FUNCTION

CB_FUNCTION btn_image_button_cb(Ihandle PTR self, int b, int e)
BEGIN_FUNCTION
  IF (b EQ IUP_BUTTON1) THEN
    DIM AS Ihandle PTR text;
    text = IupGetHandle("text");
    IF (e EQ 1) THEN
      IupSetAttribute(text, "VALUE", "pressed");
    ELSE
      IupSetAttribute(text, "VALUE", "released");
    END_IF
  END_IF
  RETURN_FUNCTION(IUP_DEFAULT);
END_FUNCTION

CB_FUNCTION btn_big_button_cb(Ihandle PTR self, int button, int press)
BEGIN_FUNCTION
  printf("BUTTON_CB(button=%c, press=%d)\n", button, press);
  RETURN_FUNCTION(IUP_DEFAULT);
END_FUNCTION

CB_FUNCTION btn_exit_cb(Ihandle PTR self)
BEGIN_FUNCTION
  RETURN_FUNCTION(IUP_CLOSE);
END_FUNCTION

MAIN
BEGIN_FUNCTION
  DIM AS Ihandle PTR dlg,
                 PTR btn_image,
                 PTR btn_exit,
                 PTR btn_big,
                 PTR btn_on_off,
                 PTR img_release,
                 PTR img_press,
                 PTR img_inactive,
                 PTR text;
  IupOpen(AT argc, AT argv);
  IupSetGlobal("UTF8MODE", "Yes");
  text = IupText(NULL);
  IupSetAttribute(text, "READONLY", "YES");
  IupSetHandle ("text", text);

  img_release = IupImage(16, 16, pixmap_release);
  IupSetAttribute(img_release, "1", "215 215 215");
  IupSetAttribute(img_release, "2", "40 40 40");
  IupSetAttribute(img_release, "3", "30 50 210");
  IupSetAttribute(img_release, "4", "240 0 0");
  IupSetHandle("img_release", img_release);

  img_press = IupImage(16, 16, pixmap_press);
  IupSetAttribute(img_press, "1", "40 40 40");
  IupSetAttribute(img_press, "2", "215 215 215");
  IupSetAttribute(img_press, "3", "0 20 180");
  IupSetAttribute(img_press, "4", "210 0 0");
  IupSetHandle ("img_press", img_press);

  img_inactive = IupImage(16, 16, pixmap_inactive);
  IupSetAttribute(img_inactive, "1", "215 215 215");
  IupSetAttribute(img_inactive, "2", "40 40 40");
  IupSetAttribute(img_inactive, "3", "100 100 100");
  IupSetAttribute(img_inactive, "4", "200 200 200");
  IupSetHandle ("img_inactive", img_inactive);

  btn_image = IupButton ("Button with image", "btn_image");
  IupSetAttribute(btn_image, "IMAGE", "img_release");
  IupSetAttribute(btn_image, "IMPRESS", "img_press");
  IupSetAttribute(btn_image, "IMINACTIVE", "img_inactive");
  IupSetAttribute(btn_image, "BUTTON_CB", "btn_image_button");
  IupSetHandle("btn_image", btn_image);

  btn_big = IupButton("Big useless button", "");
  IupSetAttribute(btn_big, "SIZE", "EIGHTHxEIGHTH");

  btn_exit = IupButton("Exit", "btn_exit");

  btn_on_off = IupButton("on/off", "btn_on_off");

  dlg = IupDialog
        (
          IupVbox
          (
            IupHbox
            (
              btn_image,
              btn_on_off,
              btn_exit,
              NULL
            ),
            text,
            btn_big,
            NULL
          )
        );

  IupSetAttributes(dlg, "EXPAND = YES, TITLE = \"C BASIC - IUP Button\", RESIZE = NO");
  IupSetAttributes(dlg, "MENUBOX = NO, MAXBOX = NO, MINBOX = NO");
  IupSetCallback(btn_exit, "ACTION", (Icallback) btn_exit_cb);
  IupSetCallback(btn_on_off, "ACTION", (Icallback) btn_on_off_cb);
  IupSetCallback(btn_image, "BUTTON_CB", (Icallback) btn_image_button_cb);
  IupSetAttribute(btn_big, "BUTTON_CB", "bigtest");
  IupSetFunction("bigtest", (Icallback)btn_big_button_cb);
  IupShowXY(dlg, IUP_CENTER, IUP_CENTER);
  IupMainLoop();
  IupClose();
  RETURN_FUNCTION(EXIT_SUCCESS);
END_FUNCTION

jrs@laptop:~/C_BASIC/iup$ ./button
BUTTON_CB(button=1, press=1)
BUTTON_CB(button=1, press=0)
BUTTON_CB(button=2, press=1)
BUTTON_CB(button=2, press=0)
BUTTON_CB(button=3, press=1)
BUTTON_CB(button=3, press=0)
jrs@laptop:~/C_BASIC/iup$
Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 20, 2014, 08:07:16 AM
Hello John,

Thanks for this heads-up on the SB memory allocator. However, don't let yourself be misguided based on that blurred and evasive description by Peter Verhas. What he is in fact describing here is a classic pool allocator (http://en.wikipedia.org/wiki/Memory_pool).

Quote from: Peter Verhas
...................................
Using the package MyAlloc you i) first create a memory segment. A memory segment is a logical entity. Whenever you allocate a new piece of memory you have to specify what memory segment you want to use for it. ii) MyAlloc does not preallocate memory, just keeps track of the memory pieces that were allocated for the segment. Whenever you want to get rid of all memories allocated for a segment you can release them all with a iii) single function call without calling free for each malloced memory piece.
...................................
The module is GNU LGPL and is part of the ScriptBasic interpreter package.
(Coloration and italization is mine)

i) "Memory segment" in professional parlance here means a large memory pool. It is allocated with malloc() just once and no other malloc'ing for individual objects, strings, etc. takes place elsewhere in the code.

ii) MyAlloc does not preallocate memory for the individual objects, strings, etc. It only preallocates it once for the entire memory pool and then just dispatches, and keeps track of, exactly what starting addresses and address ranges within the pool are assigned to various objects, strings, etc. throughout the code. Whenever an object, string, etc. is no longer needed, the dispatcher simply marks its starting address and range as vacant.

iii) The single function call to free() is made to deallocate the entire memory pool whenever there are no objects, strings, etc. left in it. If they are required for any task again, the entire memory pool is allocated anew with a single call to malloc(), and the dispatching scheme starts to work again as described above.

As for the GNU LGPL, memory pools are common knowledge and their usage may not be restricted by Peter Verhas, or Free Software Foundation, or anybody else. This statement looks plain ridiculous. :)

The Script BASIC sbhttpd multi-threaded application server that runs as a service is a good example of MyAlloc in threaded use.

Yes, ScriptBASIC looks like multithread capable, but is BaCon's structure thread safe? What's the use of SB lock mechanisms (semaphores and/or mutexes) if, for example, BaCon's code would keep its innumerous boolean flags global similar to BCX (God forgive me for vocalizing this four-letter curse again) and unprotected against inter-thread read/write conflicts?

You will have to revise BaCon's entire code and spend a lot of time debugging your modifications in a multithreaded environment unless BaCon has been written specifically as a multithreaded application from the very beginning.

This was the main idea behind my message.
Title: Re: C BASIC Runtime
Post by: John on May 20, 2014, 08:34:00 AM
I'm only converting the runtime BaCon functions to C BASIC. I don't plan on porting anything Linux/Unix specific and hope to keep C BASIC cross platform aware.  I only mentioned the SB MyAlloc option as BaCon needs some help in this area. IMHO My goal is to get a single process cross platform version of C BASIC working before looking at expanding on its feature set. Get what works working.

Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 20, 2014, 08:43:23 AM
Oh, I see. I got distracted by these words:

... for thread safe memory/garbage collection...

Probably I should've been more attentive to "memory garbage collection" that appears to be the keyword in this sentence. Sorry for that.
Title: Re: C BASIC Runtime
Post by: John on May 20, 2014, 09:45:17 PM
BaCon's string allocation and management is getting uglier by the minute. I need to take a look at MyAlloc as a possible memory management solution rather then use BaCon's scheme. I'm wondering if Charles's C BASIC memory manager he wrote in the beginning could be used? I don't want to use C++ specific features so anything else C based could be of interest. Anyone?

Title: Re: C BASIC Runtime
Post by: John on May 21, 2014, 10:56:11 AM
I created the All BASIC Developer forum so BASIC developers could colaberate and share the strenghts of each others skills. If the members of this forum no longer share the same goals, please let me know and I will stop wasting my efforts on this concept of a developer forum.

C BASIC benefits all. It started out as a community project and I hope others will contribute to get it through the rough spots. I think Peter's BaCon runtime library gives the project a big boost but BaCon wasn't designed to be looked at other than from the BASIC pre-translated form.

The current issue at hand is we need a way to DIM variables as strings and maintain them through the length of their scope. Peter already has all the #define BASIC_FUNCTION C function definitions defined and its basically a copy / paste job into the cbasic.h file.

I need to solve the string thing before going on. Is there still any interest left in C BASIC or am I just wasting my time on this also?

Here is test I did in BaCon BASIC.

Code: [Select]
GLOBAL A$
GLOBAL B$

A$ = "Hello World"
B$ = A$

Here is the BaCon C code generated for the above.

Code: [Select]
/* Rest of the program */
/* FILE hello_01.bac LINE 1 */
  A__b2c__string_var = calloc (1, sizeof (char));
/* FILE hello_01.bac LINE 2 */
  B__b2c__string_var = calloc (1, sizeof (char));
/* FILE hello_01.bac LINE 4 */
  __b2c__assign = (char *) __b2c__strdup ("Hello World");
  if (__b2c__assign == NULL)
    __b2c__assign = calloc (1, sizeof (char));
  if (A__b2c__string_var != NULL)
    free (A__b2c__string_var);
  A__b2c__string_var = __b2c__assign;
/* FILE hello_01.bac LINE 5 */
  __b2c__assign = (char *) __b2c__strdup (A__b2c__string_var);
  if (__b2c__assign == NULL)
    __b2c__assign = calloc (1, sizeof (char));
  if (B__b2c__string_var != NULL)
    free (B__b2c__string_var);
  B__b2c__string_var = __b2c__assign;
__B2C__PROGRAM__EXIT:
  return 0;
}
Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 21, 2014, 09:05:56 PM
I created the All BASIC Developer forum so BASIC developers could colaberate and share the strenghts of each others skills. If the members of this forum no longer share the same goals, please let me know and I will stop wasting my efforts on this concept of a developer forum.

C BASIC benefits all. It started out as a community project and I hope others will contribute to get it through the rough spots. I think Peter's BaCon runtime library gives the project a big boost but BaCon wasn't designed to be looked at other than from the BASIC pre-translated form.

The current issue at hand is we need a way to DIM variables as strings and maintain them through the length of their scope. Peter already has all the #define BASIC_FUNCTION C function definitions defined and its basically a copy / paste job into the cbasic.h file.

I need to solve the string thing before going on. Is there still any interest left in C BASIC or am I just wasting my time on this also?

John,

You should understand that it is impossible to implement a BASIC-to-C translator by means of C preprocessing alone. I repeat once again, if it were possible then it would have been done in BCX fifteen years ago.

It relates to very many aspects of BASIC and not only to memory allocation. BASIC is too high a programming level for a verbatim low-level ANSI C equivalent. If you take away its associated precompiled libraries, a bare-bones ANSI C is effectively almost as low as a macro assembler and even these libraries are written at a substantially lower level of machine code abstraction than "simple" standard BASIC procedures.

If you insist on following your path, you will have to re-create yet another instance of BCX. Does the BASIC community really need one?

As for a simple solution to your Dim ... As String [* N] problem, have a look at BCX' ring allocator (a.k.a. Circular Buffer (http://c2.com/cgi/wiki?CircularBuffer)). BCX implements global dynamic and fixed-length strings, as well as all local static strings, as C program-level static char* entities. The allocation and garbage collection of temporary string variables in a function is performed with the aid of a circular linked list of reusable char pointers and a general-purpose malloc()/free() allocator.

But you will have to add three or four full-fledged C functions to your C BASIC include file to implement this simple functionality. And end up with a hundred similar functions more in another fifteen years from now.

The redundant C BASIC idea was a stillborn baby from its very beginning.


Kind regards,

Mike Lobanovsky
BCX developer veteran (hehehe...)
Title: Re: C BASIC Runtime
Post by: John on May 21, 2014, 09:29:34 PM
Quote
You should understand that it is impossible to implement a BASIC-to-C translator by means of C preprocessing alone.

I think AIR did an outstanding job with his C++ variation of C BASIC he calls JADE.

C BASIC and using the preprocessor is an original idea. (not a BCX reject) I have already proven that C BASIC makes C code easier to read and use. I could stop there and just use it in SB. I want to see how far I can take this. You said the magic word. (impossible)

Currently C BASIC builds on the work Peter Verhas had done with the extensive macros and defines for the Script BASIC API. Without them it would be near impossible to embedded the language other than by Peter himself. C BASIC looks more like BASIC to me than it does C. (without any loss of the power of C)

I'm not going anywhere near BCX. (been there, done that) The only method so far that make any sense to me is what is working and rock solid in SB. (MyAlloc) I have been pestering Peter (PvE ) for years about BaCon's string handling and something better needs to be done. It has finally bitten me in the ass. I think Peter's (PvE) BaCon runtime functions will put C BASIC in a position to used as a full fledged BASIC rather than a mask to cover up cryptic C.

Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 21, 2014, 09:41:27 PM
John,

You put a question:
Quote
Is there still any interest left in C BASIC...?

Now you have my vote as a BASIC community member:

Nay!

Quote
... extensive macros and defines ...

Extensive macros can easily turn a simple crystal clear 4.5KB C executable into a 60KB piece of bloatware very much like careless inlines. Go figure.

Reusable C functions yield a lot neater C code.
Title: Re: C BASIC Runtime
Post by: John on May 21, 2014, 10:06:43 PM
Quote
Extensive macros can easily turn a simple crystal clear 4.5KB C executable into a 60KB piece of bloatware.

What are you talking about? The preprocessor expands (-E) the macros/defines back to their C equivalent before compiled. (see example above) There is no bloat from using #defines.

 
Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 21, 2014, 10:21:22 PM
This is exactly what I'm talking about. If you manage to describe the above-mentioned ring allocator as a multiline #define (a macro), your preprocessor will re-duplicate (expand) a new instance of entire ring allocator into each and every function that would happen to need to create even a single temporary empty string variable. The same happens with C functions carelessly declared as inline - they ceise to be regarded as standalone functions and are treated as preprocessor macros, i.e. re-duplicated (inlined) in each place where they happen to be "called".

This is how you end up with 60KB of C-equivalent machine code where you're expecting to see 6KB at the most.

You need to resort to genuine C functions instead of a simple header file if you want to have worthwhile BASIC-to-C translation. You can't beat Kevin Diggins on that. :)
Title: Re: C BASIC Runtime
Post by: John on May 21, 2014, 10:31:42 PM
The BaCon libraray is linked in with only the runtime functions used. The memory manager (MyAlloc) is a set of functions and called when needed. That doesn't pan out with what you are saying.

Keep in mind that BaCon is a text to text translator. The end result is C code. I see no difference making C's already BASIC like flow look more like BASIC with symbol substitutions and doing what BaCon does now calling it's runtime. I'm just skipping the text to text translation step.

This is the #define for CHOP(). (see CHOP C BASIC runtime function above)

Code: [Select]
#define CHOP(...) cbrt_chop(__VA_ARGS__, 0)


Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 21, 2014, 11:30:20 PM
Even if your task is obviously hiding the ...-to-C stage of translation from the user's eyes by letting the C compiler read your C BASIC header and use the BaCon library with or without the addition of MyAlloc for immediate compilation, you will not get by with a C BASIC header file alone. You need much deeper parsing capabilities to efficiently translate Dim ... As String and similar declarations and other BASIC language features to equivalent C.

Forget the header file. Write a simple recursive descent parser that would turn your canonical-BASIC "X BASIC" or whadayacallit sources into decent C equivalents without those horrible semicolons or neoteric BEGIN_FUNCTION placeholders. In short, go the BCX way and try to keep your "X BASIC" syntax closer to tradition.

I repeat I do not see any sense or benefit in C BASIC over BCX. The latter does a much much better job of converting a BASIC-style dialect to C. Replace BCX' ring allocator with your MyAlloc routines if you want to. What's the problem of forking the open-source GNU GPL BCX project for that if you wanna stay open-source all the way through yourself? Disgust towards that Kevin Diggins character? ;) Come on, John! :D And you can simply add a BCX post-processing step of automatic C compilation and immediate deletion of intermediate C code files from your disk. What else would you want or should the user need and why?
Title: Re: C BASIC Runtime
Post by: John on May 21, 2014, 11:44:34 PM
For grins embed in FBSL a BCX version of the C BASIC like integer Mandelbrot benchmark of Ed's. After about 5 pages of GLOBAL defines, we might start seeing user code and then more pages of runtime code with IF switches in case the function is used.  :o

Sorry, not interested.
Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 21, 2014, 11:51:22 PM
After about 5 pages of GLOBAL defines, we might start seeing user code and then more pages of runtime code with IF switches in case the function is used.

Sorry to say it John but that's the only way to keep a BASIC-to-C translator syntax consistent, reliable and fool-proof on both ends.
Title: Re: C BASIC Runtime
Post by: John on May 21, 2014, 11:59:36 PM
Look at the Script BASIC GFX extension module (https://bitbucket.org/ScriptBasic/c-basic/src/d7003c69f6f3035aab89a2d4c43dbe1e7e514f80/SBext/SDL_gfx/interface.c?at=master) I did with C BASIC on the C BASIC Bitbucket site. Looks like a BASIC program to me and I haven't added in the BaCon runtime yet.

C BASIC is not a translator. It is a C preprocessor overlay and BASIC runtime library. As one starts feeling more comfortable with C, the programmer can ween them self off the C BASIC crutch. It's that simple. Think of C BASIC as your first paint by numbers set.  :)
Title: Re: C BASIC Runtime
Post by: Mike Lobanovsky on May 22, 2014, 12:28:14 AM
Ay-ay captain!

But put me ashore first. :D

P.S.

Quote
besSUB_START
  DIM AS long *p;
  besMODULEPOINTER = besALLOC(sizeof(long));
  IF (besMODULEPOINTER EQ NULL) THEN_DO RETURN_FUNCTION(0);
  p = (long*)besMODULEPOINTER;
  RETURN_FUNCTION(0);
besEND

besSUB_FINISH
  DIM AS long *p;
  p = (long*)besMODULEPOINTER;
  IF (p EQ NULL) THEN_DO RETURN_FUNCTION(0);
  RETURN_FUNCTION(0);
besEND

You can prepend (https://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Attribute-Syntax.html) your function declaration list with an __attribute__((noreturn)) attribute and your GCC will allow the redundant trailing RETURN_FUNCTION(0); statements to be omitted from your pseudo BASIC Subs.
Title: Re: C BASIC Runtime
Post by: John on May 22, 2014, 07:59:48 AM
Getting back to the original request.

Anyone have any ideas how we can emulate BASIC like string usage in C BASIC?

I'm looking for a BASIC like way to do string assignments.