Close

99 Bottles of Recursive Pascal Beer on Humpty Dumpty's Wall

A project log for Rubidium 2.0

This is an all in one spectrum and logic analyzer, robotics control platform, and modular synthesizer with audio in and sheet music out!

glgormanglgorman 10/21/2021 at 11:230 Comments

As you probably know time travel is probably impossible, at least for practical purposes, no matter what Calvin Klein says.  Neither are you likely to be unbreaking an egg anytime soon, no matter how hard all of the king's horses and all of the king's men may hope for.  On the other hand, as far as tricking a C++ compiler into chowing down on Pascal programs with "only" minimal modification; well that one might not nearly be as difficult as inventing time travel or warp drive might actually turn out to be in practice.  Now one of the problems with getting a C++ compiler to chow down on Pascal source is the fact that Pascal allows for so-called "nested procedures or functions" which means that PROCEDURE A can have PROCEDURES B and C declared inside A, and also maybe PROCEDURES D and E declared inside A in such a way that A can call B which calls C, which then calls B over and over again recursively, which might be used create a "wall object" and 99 "beer" objects using recursion on the stack (if so desired) through recursion, and then have B or C call A again in a re-entrant fashion so that A can now call procedures D and E, when then operate recursively to pull down some of the bottles and pass them around., at least until an "out of beer exception occurs."  Not that you can't do that in C++, but can it be done with DEEPLY nested and mutually recursive functions - and in such a way that when you look at the source code it looks like a Pascal program has been converted to use nested namespaces - which is allowed - just not nested functions.  Now let's make it even harder, AND not add any new passed parameters to the original functions, since one of the nice features about Pascal nested procedures, is that the inner nested procedures have access to the outer procedure's local variables, that is to say without having to de-reference any passed pointers, and then otherwise use a WITH statement, (which would be "evil", and which also doesn't exist in C++.

Now to throw another log on the fire, although a template based on 99 bottles of recursive Pascal beer might be useful for implementing fun things like editors with 99 levels of undoing, or Tiny-OS kernels that support up to 99 or more concurrent processes; there are actually even bigger fish to fry.

Even bigger fish to fry?  How about the fact that Pascal allows for some very nasty, even though it is not quite Halloween yet, Here is some code that looks like it just might have come straight out of some "sequel that never got made to the Rocky Horror Picture Show" like data structures.  Like this one from the Pascal source of UCSD Pascal: (So yeah, "Let's do the time warp again!")

IDENTIFIER = RECORD
    NAME: ALPHA; LLINK, RLINK: CTP;
        IDTYPE: STP; NEXT: CTP;
            CASE KLASS: IDCLASS OF
                KONST: (VALUES: VALU);
                FORMALVARS,
                ACTUALVARS: (VLEV: LEVRANGE;
                VADDR: ADDRRANGE;
                CASE BOOLEAN OF
                    TRUE: (PUBLIC: BOOLEAN));
                      FIELD: (FLDADDR: ADDRRANGE;
                        CASE FISPACKD: BOOLEAN OF
                    TRUE: (FLDRBIT,FLDWIDTH: BITRANGE));
                      PROC,
                      FUNC:  (CASE PFDECKIND: DECLKIND OF
                        SPECIAL:  (KEY: INTEGER);
                        STANDARD: (CSPNUM: INTEGER);
                        DECLARED: (PFLEV: LEVRANGE;
                        PFNAME: PROCRANGE;
                        PFSEG: SEGRANGE;
                              CASE PFKIND: IDKIND OF
                                  ACTUAL: (LOCALLC: ADDRRANGE;
                                  FORWDECL: BOOLEAN;
                                  EXTURNAL: BOOLEAN;
                                  INSCOPE: BOOLEAN;
                              CASE BOOLEAN OF
                                  TRUE: (IMPORTED:BOOLEAN))));
                    MODULE: (SEGID: INTEGER)
                    END;

 Now I know why they call it the "Dragon Book", but this is another story.  Still, does this mean that the compiler has to use mutually recursive nested functions in order to correctly parse variant record types that themselves might contain a whole zoo of variant sub-records, which themselves contain nested variant records? 

 In other news, using not much more than "stone knives and bear skins" I have managed to convert about 4000+ lines of UCSD Pascal to C++, while "somehow" finding a way to allow it to at least appear that I am converting some highly nested and potentially mutually recursive procedures into what looks like mutually nested recursion in C++, by using "only" namespaces (and perhaps some snake oil along with the right source of smoke and mirrors in other places like my earlier Pascal style in C++ WRITELN  hack).

Don't believe me?  Well, it does compile, so far up though, and including the DECLARATIONPART and UNITPART segments.  Once BODY is done I will have a compiler that will be able to be run on the Propeller or the Arduino, among other things, maybe even a NOR computer.  Check out "declaration1.cpp" if you don't believe it!  Warning!  Not only is this software "GNU" and without warranty, along with any other applicable restrictions, I can pretty much guarantee that not only does it have bugs, but it probably has a few more bugs that it didn't have when first released in 1979 or thereabouts.    

Discussions