Author Topic: PulsarBASIC - Teaser thread  (Read 7103 times)

Cybermonkey

  • Administrator
  • *****
  • Posts: 0
Re: PulsarBASIC - Teaser thread
« Reply #15 on: June 13, 2019, 08:24:37 AM »
If you are interested, I can post a new version with both features mentioned above.
That would be highly appreciated.  :D

New version is attached.
Thanks a lot. That looks quite handy. I will try to implemented it in AllegroBASIC on Saturday.

Aurel

  • Guest
Re: PulsarBASIC - Teaser thread
« Reply #16 on: June 13, 2019, 08:13:48 PM »
Yes Cyb
it works of course
but only on 32bit

Cybermonkey

  • Administrator
  • *****
  • Posts: 0
Re: PulsarBASIC - Teaser thread
« Reply #17 on: June 14, 2019, 07:11:06 AM »
Yes Cyb
it works of course
but only on 32bit
Why so? I compiled it on Linux 64bit and it works fine. On Windows I usually compile my programs for 32bit destination.

Aurel

  • Guest
Re: PulsarBASIC - Teaser thread
« Reply #18 on: June 14, 2019, 08:40:44 AM »
No i was talking about my old binder written in Emergence basic 32bit.
I don't tried this one ..because i have in plan to use Oxygen basic for that job.
But of course i will try Ed binder too.

Cybermonkey

  • Administrator
  • *****
  • Posts: 0
Re: PulsarBASIC - Teaser thread
« Reply #19 on: June 14, 2019, 10:16:00 AM »
No i was talking about my old binder written in Emergence basic 32bit.
I don't tried this one ..because i have in plan to use Oxygen basic for that job.
But of course i will try Ed binder too.
Ok, now I understand.  :)

Aurel

  • Guest
Re: PulsarBASIC - Teaser thread
« Reply #20 on: June 14, 2019, 10:48:34 AM »
Well
Ed Binder is not just binder than
PLO interpreter + binder
what is PLO i am not sure - looks like
some sort of pascal language ..right Ed?
Is this bytecode compiler?

Cybermonkey

  • Administrator
  • *****
  • Posts: 0
Re: PulsarBASIC - Teaser thread
« Reply #21 on: June 14, 2019, 12:00:10 PM »

Ed Davis

  • Guest
Re: PulsarBASIC - Teaser thread
« Reply #22 on: June 14, 2019, 01:20:14 PM »
Ed Binder is not just binder than

There are two C programs in the zip file:
binder.c - which is just a binder.
pl0.c - pl/0 interpreter.  Once compiled, this one handles either bound programs or programs passed on the command line.

PLO interpreter + binder
what is PLO i am not sure - looks like
some sort of pascal language ..right Ed?
Is this bytecode compiler?

PL/0 was a simple language Wirth (Algol-W/Pascal/Modula/Oberon creator) created for teaching students how to write compilers, in the compiler courses he taught.  It is not a strict subset of Pascal - a few minor differences.  First book about it was Algorithms + Data Structures = Programs, circa 1976.   An execellent book!  You can get it for a song on Amazon - highly recommended, even today.  He also has an excellent compiler book, in PDF form, on his website.  Again, this one is also highly recommended.  If you have any interest in compilers and interpreters  :)

Anyway, I flunked my compilers class, but about 30 years ago (has it been that long?), I took up the subject again, and translated Wirth's Pascal version of PL/0 to C.  Recently I updated it for Linux.

And yes, it is a byte-code interpreter (Wirth called them p-codes).

Code: [Select]
    do {
        int f_ret;      /* instruction register */
        const Code ir = code[pc];
        pc++;
        switch (ir.opcode) {
            case o_lit: top++; stack[top] = ir.adr; break;
            case o_lod: top++; stack[top] = stack[display[ir.level] + ir.adr]; break;
            case o_sto: stack[display[ir.level] + ir.adr] = stack[top]; top--; break;
            case o_cal:  /* generate new block mark */
                stack[top + 1] = display[ir.level + 1];
                stack[top + 2] = pc;
                display[ir.level + 1] = top + 1;
                pc = ir.adr;
                break;
            case o_rtf:
                f_ret = stack[top];
                // fall-thru
            case o_rtp:
                top = display[ir.level];
                display[ir.level] = stack[top];
                pc = stack[top + 1];
                top -= (ir.adr + 1);
                if (ir.opcode == o_rtf) {
                    top++;
                    stack[top] = f_ret;
                }
                break;
            case o_int: top += ir.adr; break;
            case o_jmp: pc = ir.adr; break;
            case o_jpc:
                if (stack[top] == 0)
                    pc = ir.adr;
                top--;
                break;
            case o_pop: top--; break;

            case o_neg: stack[top] = -stack[top]; break;
            case o_add: top--; stack[top] += stack[top+1]; break;
            case o_sub: top--; stack[top] -= stack[top+1]; break;
            case o_mul: top--; stack[top] *= stack[top+1]; break;
            case o_div: top--; stack[top] /= stack[top+1]; break;
            case o_mod: top--; stack[top] %= stack[top+1]; break;
            case o_equ: top--; stack[top] = stack[top] == stack[top+1]; break;
            case o_neq: top--; stack[top] = stack[top] != stack[top+1]; break;
            case o_lss: top--; stack[top] = stack[top] <  stack[top+1]; break;
            case o_geq: top--; stack[top] = stack[top] >= stack[top+1]; break;
            case o_gtr: top--; stack[top] = stack[top] >  stack[top+1]; break;
            case o_leq: top--; stack[top] = stack[top] <= stack[top+1]; break;
            case o_and: top--; stack[top] = stack[top] && stack[top+1]; break;
            case o_or:  top--; stack[top] = stack[top] || stack[top+1]; break;

            case o_rdi: {
                int temp;

                fflush(stdout);
                if (scanf("%d", &temp) < 0)
                    perror("scanf: ");
                top++;
                stack[top] = temp;
                break;
            }
            case o_wrl: printf("\n"); break;
            case o_wrt: printf("%d ", stack[top]); top--; break;
            case o_wrs: {
                int len = lit_data[ir.adr];
                char *cp = &lit_data[ir.adr + 1];
                printf("%*.*s", len, len, cp);
                break;
            }
            default:
                printf("Invalid opcode %d at position %d\n", ir.opcode, pc - 1);
                // fall-thru
            case o_hlt: pc = 0; break;
        }
        if (top > last_stack) {
            last_stack = top;
            if (verbose)
                printf("stack increased to %d at %d\n", top, pc);
        }
    } while (pc > 0);

Only data type is integer.  But it does have nested procedures, which can be interesting; no parameters though.

It is definitely worth the time to study Wirth's compilers - after PL/0, take a look at Pascal-S.

Ed Davis

  • Guest
Re: PulsarBASIC - Teaser thread
« Reply #23 on: June 14, 2019, 01:57:27 PM »
There are two C programs in the zip file:
binder.c - which is just a binder.
pl0.c - pl/0 interpreter.  Once compiled, this one handles either bound programs or programs passed on the command line.
...
 no parameters though.

I forgot!  I updated this one to include parameters.  Plus, blocks are more Modula2/Oberon like than Pascal.  So not strictly PL/0, more PL/0+ :-)

Aurel

  • Guest
Re: PulsarBASIC - Teaser thread
« Reply #24 on: June 14, 2019, 03:47:36 PM »
Ed
sorry Cyb if i babeling on your topic...

I see on many your and other authors
stack-this ,..stack--that

How should look stack-less interpreter?
like mine..even i use some sort of stack for FOR/GOSUB blocks

Cybermonkey

  • Administrator
  • *****
  • Posts: 0
Re: PulsarBASIC - Teaser thread
« Reply #25 on: June 14, 2019, 08:26:45 PM »
Ok, back to topic, although this thread is already far away from it ...
I've got a question to the load_script function: is the complete listing saved in the "static char *script"?
I actually don't get where's the decision if the script is bound and executed or loaded from a file.

Ed Davis

  • Guest
Re: PulsarBASIC - Teaser thread
« Reply #26 on: June 15, 2019, 12:36:33 AM »
I've got a question to the load_script function: is the complete listing saved in the "static char *script"?

Yes, in load_script(), starting at line 1036:

Code: [Select]
    script = malloc(script_size);

    /* seek to the start of the script */
    if (fseek(fp, -(script_size + extra_size), SEEK_END) != 0) {
        perror("load_script fseek end 2");
        return false;
    }

    size_read = fread(script, 1, script_size, fp);

I actually don't get where's the decision if the script is bound and executed or loaded from a file.

In the main() routine.

It loops around the args, and if one does not start with "-", then it assumes it is a filename.

Then at line 1093:

Code: [Select]
    if (!fn && !load_script()) {
        show_help();
        return 2;
    }

So, if the fn is NULL (e.g., !fn) && !load_script() -- load_script() is a boolean -- we show the help and exit.

I probably need more comments - sorry about that!

If you have other questions, feel free to ask.


Cybermonkey

  • Administrator
  • *****
  • Posts: 0
Re: PulsarBASIC - Teaser thread
« Reply #27 on: June 15, 2019, 07:51:09 AM »
Ok, thanks, this I understood. Now I still don't get the decision whether the script or the file is executed. There's that "init_scan" function; does it only execute if a file is loaded otherwise the "load_script" is used? (Sorry for my dumb questions but as I said C is rather confusing for me.)

In AllegroBASIC it's that simple (for now):
Code: [Select]
if (argc>1) {
if(mb_load_file(bas, argv[1]) == MB_FUNC_OK)
_alloc_data_seq();
mb_run(bas,true);
_free_data_seq();
}
else {
tinyfd_messageBox("No Script", "AllegroBASIC 0.6.5\nUsage: allegrobasic[.exe] script.bas", "ok", "error", 1);

}

And in PulsarLua the decision whether to use the script or the file, looks like this (Pascal is so much easier to read...):
Code: [Select]
if isbound = true then
begin
if luaL_dostring (L,PChar(prog))<>0 then
begin
//show if an error occured
Messagebox(1,'Error',lua_tostring (L,-1));
closeapplication;
halt;
end;

end
else
  if (luaL_dofile(L, script))<>0 then
   begin
//show if an error occured
Messagebox(1,'Error',lua_tostring (L,-1));
closeapplication;
halt;
  end;
  lua_close(L);
end.
("isbound" is a boolean which is filled at runtime - if I found out that the script is bound then it's true otherwise false.)

Cybermonkey

  • Administrator
  • *****
  • Posts: 0
Re: PulsarBASIC - Teaser thread
« Reply #28 on: June 15, 2019, 03:11:36 PM »
Ok, forget my last question. It works!!  :D
No I will try the compilation of AllegroBASIC on Windows. Keep your fingers crossed ...
Edit: added a screenshot from the new AllegroBASIC editor including the output of the binder program.
« Last Edit: June 15, 2019, 07:39:51 PM by Cybermonkey »

Cybermonkey

  • Administrator
  • *****
  • Posts: 0
Re: PulsarBASIC - Teaser thread
« Reply #29 on: June 16, 2019, 07:45:46 AM »
Phew, it took me over an hour to figure out how to compile it on Windows. The problem was that the "load_script" function needs <windows.h> which interferes with  <allegro.h>.
So if any of you will ever use (the old version of) Allegr: use <winalleg.h> instead of <windows.h>.
But anyway, this is about PulsarBASIC, not AllegroBASIC, so the latter one will get its' own thread.