Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature request] Three levels of "local variables" #651

Open
kristoffermads opened this issue Jun 5, 2021 · 2 comments
Open

[Feature request] Three levels of "local variables" #651

kristoffermads opened this issue Jun 5, 2021 · 2 comments
Labels
enhancement New feature or request Low Priorty Low priority or will be ignored...

Comments

@kristoffermads
Copy link

kristoffermads commented Jun 5, 2021

When I first started programming TRSE I failed to understand why my code would sometimes not compile due to variables already being declared. It was always variables inside functions or procedures - and often my counters or "temp" / "counter" variables. As a main "back then" i386 programmer, i failed to understand the problem, until it was explained. But nevertheless, the problem fr me remains even to this day, and I have come to name my variables with their function/procedure names as prefixed.

To remedy this problem i propose implementing three levels of local variables.

Level 1: (default level for new projects)
Variables can only be declared in global space - perhaps even only one place (one var keyword). This codesamples will therefore result in a compiler-error:

procedure MyFunc(param1: byte);
var
   x: byte;
begin
...

Whereas this will work just fine:

var x: byte;
procedure MyFunc(param1:byte)
begin
.. 

Parameters are counted as "local variables" in this instance, which means that this code, in Level 1, should fail:

var x: byte;
procedure MyFunc(x:byte)
begin
.. 

Level 2 (seems to be default for current projects)
Local variables are on compile-time prefixed with their function/procedure name and then included into the global space. This will cause local variables to use the same variables over and over, thus overwriting its own memory - only a problen on recursive function calling.

This procedure will therefore not yield the expected result, in Level2:

procedure WhatIsMyNumber(number:byte)
var 
  the_number : byte; // apriori as non-6502 coder, one would think this is unique to each call of this function.
begin
   if (number = 0) then
   begin
   end else
   begin
      the_number := number;
      WhatsIsMyNumber(number-1);
      if (the_number <> number then) // this will be true
      begin
        // should not happen with "regular stack" - but it does with TRSE Level 2
      end
   end
end
WhatIsMyNumber(10);
.. 

Parameters are also prefixed which means this code in Level 2 will not fail:

var x: byte;
procedure MyFunc(x:byte)
begin
.. 

Level 3
Will by default work as level2, except it introduces the option to

procedure WhatsIsMyNumber(number:byte) stack
var 
  the_number:byte;
begin
  if (number = 0 then)
  begin
    // done
  end
  else
  begin
    the_number := number;
    WhatsIsMyNumber(number-1);
    if (the_number <> number then) // this will be false
    begin
      // this will not happen
    end
  end
end

WhatIsMyNumber(10);
...

What will really happen here, is a userdefined stack will be utilized where each function/procedure contains a "chunk" of data - I will try to pseudo-code something here that might make sense:


@UserStack = $2000
@UserStackPointer = $2000

// compiler-time records
WhatIsMyNumber_record = record
  number:byte;
  the_number:byte;
end;

// variable which only exists for the purpose of illustration - it should probably "just" be UserStackPointer
var
    CurrentRecordCall : WhatIsMyNumber = ^UserStackPointer;

// the function-call
UserStackPointer += sizeof(WhatIsMyNumber_record);
JSR WhatIsMyNumber
UserStackPointer -= sizeof(WhatIsMyNumber_record);

// the function itself
procedure WhatIsMyNumber()
var 
  number, the_number:byte;
begin
  // here we unpack
  number := CurrentRecordCall.number;
  the_number := CurrentRecordCall.the_number;


optional: include a @UserStackMaxsize which guards against overflow, maybe even with a callback address, like so:

@UserStack = $2000
@UserStackPointer = $2000
@UserStackMaxSize = $1000
@UserStackOverflow = #MyFunc

Where each stack-"push" will check if it overflows, and if that happens it will JSR to #MyFunc

The idea is just that of classes, chunks of data, pushed to the current userdefined stackpointer, then the pointer is moved forward, the procedure is called and the memory unrolled into local variables "as regular".

Level 3 will bes low and take a bunch of memory, but it will be entirely voluntarily.

Another option is to merge Level 2 and Level 3, but the explained Level 3 features here, only works when the keyword "stack" is appended to the function call, like this:

procedure WhatIsMyNumber() stack
var 
  number, the_number:byte;
begin
  // will be stacked
@kristoffermads
Copy link
Author

Addendum: Maybe differentiate between the keyword "stack" ($55) and "userstack" (as given in my proposal) where userstack will be significant slowed.

@leuat leuat added enhancement New feature or request Low Priorty Low priority or will be ignored... labels Sep 28, 2021
@tomcss
Copy link

tomcss commented Apr 11, 2023

I would also very much enjoy the proposed Level 2, as that's what I'm doing manually now..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Low Priorty Low priority or will be ignored...
Projects
None yet
Development

No branches or pull requests

3 participants