LBLBASIC

Bronbestanden van LBLBASIC gebruiken conventioneel de extensie .bal (BASIC with labels).

Projectbestanden

Het project bestaat uit vier hoofdbestanden:

  • lblbasic.py: De referentie-implementatie die wordt gebruikt voor het ontwikkelen en testen van taalwijzigingen. Deze maakt uitsluitend gebruik van de Python-standaardbibliotheek.
  • lblbasic.awk: De oorspronkelijke referentie-implementatie. Deze is behouden als een compacte, draagbare implementatie van de taal zoals deze was voordat de referentie naar Python werd overgezet.
  • lblbasic.bal: Een implementatie van LBLBASIC geschreven in BAL zelf.
  • lblbas.bas: De reeds geconverteerde MBASIC-versie van lblbasic.bal. De kortere bestandsnaam is bewust gekozen voor CP/M-bestandssystemen.

De Python- en MBASIC-versies zijn bedoeld om dezelfde BAL-taal te implementeren. De testsuite controleert de Python-port tegen de awk-versie voor de functies die ze delen.

Ondersteunde functionaliteiten

FunctionaliteitPythonBAL/MBASICLegacy awk
Labels en symbolische numerieke substitutieJaJaJa
Gestructureerde IF, WHILE, DO, EXIT en CONTINUEJaJaJa
OFF/ON onderdrukking en behoud van lege regelsJaJaJa
Configureerbare brontekens en limieten voor regelnummersJaJaJa
INCLUDE bronbestandenJaJaNee
CONST numerieke symbolenJaJaNee
OPT/ENDOPT, optionele NOT en ERRORJaJaNee
Numerieke STACK/PUSH/POPJaJaNee
Trim, newline en label-only comment CLI-optiesJaNeeNee

Ondanks deze verschillen gebruikt lblbasic.bal bewust alleen de gemeenschappelijke legacy-subset in zijn eigen uitvoerbare broncode. De awk-vertaler kan daarom nog steeds de native MBASIC-implementatie genereren.

Snelstart

Gegeven een BAL-bronbestand:

':start
print "Hello"
goto @done
':unused
print "You should not see this"
':done
end

Voer het volgende uit: python3 lblbasic.py program.bal > program.bas

De output zal gewoon genummerd BASIC zijn, bijvoorbeeld:

10 print "Hello"
20 goto 30
30 end

Voor CP/M/MBASIC moeten gegenereerde bestanden indien nodig worden geconverteerd naar DOS/CP/M-regelafbrekingen voordat ze worden overgezet: unix2dos program.bas

Dit geldt ook voor .bal-bronbestanden die direct door de MBASIC-implementatie worden gelezen.

De BAL-taal

BAL is bewust een kleine uitbreiding van gewoon BASIC. De preprocessor analyseert of evalueert geen BASIC-expressies; expressies blijven BASIC-tekst en worden later geëvalueerd door de doel-BASIC-interpreter.

De belangrijkste toevoegingen zijn:

  • Symbolische labels
  • Symbolische verwijzingen naar regelnummers
  • Gestructureerde IF
  • WHILE-loops
  • DO-loops
  • EXIT en CONTINUE
  • Brononderdrukking met OFF / ON
  • Tekstuele inclusie van broncode
  • Genummerde numerieke constanten
  • Optionele broncodeblokken tijdens het compileren
  • Een numerieke save/restore stack

Alles wat hier niet bij staat, wordt doorgegeven als standaard BASIC.

Symbolische labels

Een labeldefinitie wordt geschreven als een apostrof gevolgd door het labeldefinitie-teken (standaard ::): ':start

Een verwijzing gebruikt het symbool voor symbolische referentie (standaard @): goto @start gosub @worker

Labels zijn ongevoelig voor hoofd- en kleine letters: ':Finished goto @finished (dit is geldig)

Voorafgaande en navolgende witruimte in een labeldefinitie wordt genegeerd. Labels mogen letters, cijfers en underscores bevatten, maar het eerste teken moet een letter of underscore zijn.

Voorbeelden:

  • ':main
  • ':read_record
  • ':retry2
  • ':_internal

Symbolische verwijzingen als numerieke waarden

Een symbolische referentie is niet beperkt tot GOTO of GOSUB. Buiten geciteerde strings en commentaren wordt een symbolische referentie simpelweg vervangen door het BASIC-regelnummer dat aan dat label is toegewezen.

Voorbeelden van legale BAL-syntaxis:

  • goto @foo
  • gosub @foo
  • if x then @foo
  • on n goto @one,@two,@three
  • print 10 + @foo

Referenties binnen geciteerde strings en commentaren worden niet vervangen: print "goto @foo" ' dit vermeldt @foo maar verwijst er niet naar

Niet-gedefinieerde labels blijven ongewijzigd en veroorzaken een waarschuwing.

Output van labels en commentaren

BAL-labeldefinities zijn in feite commentaar-achtige bronregels. Of labelregels en commentaren verschijnen in de gegenereerde output, hangt af van de comments / COMMENTS instelling.

Wanneer commentaren zijn uitgeschakeld, verbruiken labeldefinitie-regels geen gegenereerde BASIC-regelnummers, tenzij targetrem / TARGETREM vereist dat de labelregel zelf het vertakkingsdoel is.

De Python-vertaler kan labeldefinitie-commentaren onafhankelijk bewaren met -L/--keep-label-comments. De symbolische label verwijst dan naar de volgende gegenereerde regel in plaats van naar zijn eigen commentaarregel.

Labels in de gereserveerde __LBLB_ namespace zijn gegenereerde implementatiedetails. Hun definities worden nooit uitgegeven en worden nooit commentaardoelen, ongeacht de instellingen.

Blanke regels of regels die alleen uit witruimte bestaan, worden standaard verwijderd. De optie -k/--keep-blanks in de Python-vertaler bewaart deze als kale, ongenummerde outputregels. Deze verbruiken geen BASIC-regelnummers.

Genoemde numerieke constanten

Python en BAL/MBASIC ondersteunen genoemde, getekende decimaal-gehele constanten: 'CONST! UMASK=125 'CONST! OFFSET=-20 X=X+@UMASK Y=Y+@OFFSET

CONST! gebruikt het geconfigureerde gestructureerde suffix en produceert geen BASIC-regel. De naam volgt dezelfde regels als symbolische labels, terwijl de waarde beperkt is tot een optionele + of - gevolgd door decimale cijfers. Expressies, breuken, exponentiële notatie, type-suffixen en commentaren aan het einde van de regel worden niet geaccepteerd.

Constanten en labels gebruiken aparte interne tabellen, maar delen het symbool voor symbolische referentie (@ standaard). Een referentie mag voorafgaan aan de definitie van de constante. Namen zijn ongevoelig voor hoofd- en kleine letters; een naam mag niet meer dan één keer gedefinieerd worden en mag niet zowel een label als een constante zijn.

Optionele broncodeblokken

Python en BAL/MBASIC kunnen broncode includeren of onderdrukken op basis van een letterlijke waarde of een eerder gedefinieerde constante:

'CONST! DEBUG=1
'OPT! @DEBUG
PRINT "debugging is enabled"
'ENDOPT!

'OPT! NOT @DEBUG
PRINT "included only when debugging is disabled"
'ENDOPT!

'OPT! 0
PRINT "this source is omitted"
'ENDOPT!

Een waarde van nul onderdrukt het blok; elke niet-nul getekende decimale integer includert het. De operand moet een geheel getal of een constantereferentie zijn, optioneel voorafgegaan door NOT om het resultaat om te keren.

OPT!-blokken kunnen genest worden. Binnen een reeds onderdrukt OPT! of OFF! gebied worden geneste opties niet geëvalueerd, hoewel OPT! en ENDOPT! nog steeds in balans moeten zijn.

Een actieve optionele configuratie kan de vertaling bewust stopzetten met een diagnostisch bericht: 'OPT! NOT @IGUESS 'ERROR! You forgot to enable IGUESS 'ENDOPT!

ERROR! behandelt de rest van de regel als platte tekst. Het voert geen symbolische substituties uit, produceert geen BASIC-regel en zorgt ervoor dat de vertaling faalt zonder gedeeltelijke output.

Includeren van bronbestanden

De Python-referentie ondersteunt tekstuele inclusie van broncode: 'INCLUDE! common.bal

De directieve moet op een eigen fysieke bronregel staan. De bestandsnaam is de rest van de regel. De directieve is ongevoelig voor hoofdletters en wordt niet uitgegeven, zelfs niet als commentaren bewaard blijven.

Een geïncludeerd bestand gedraagt zich alsof de fysieke regels de directieve vervangen. Labels, gestructureerde blokken, de staat van brononderdrukking en de gegenereerde regelnummering worden gedeeld over bestandsgrenzen. Inclusies binnen een actief OFF!-gebied worden genegeerd.

In Python worden relatieve bestandsnamen opgelost vanuit de directory van het includerende bestand. Onder MBASIC worden bestandsnamen direct aan CP/M doorgegeven. Geneste inclusies zijn beperkt tot 20 niveaus; actieve recursieve cycli leiden tot fouten.

Numerieke Save/Restore Stack

De Python- en BAL/MBASIC-implementaties bieden een kleine numerieke stack voor het bewaren van scalaire variabelen rondom subroutine-aanroepen:

STACK! 200
PUSH! X%,Y!,Z#
GOSUB @worker
POP! X%,Y!,Z#

STACK! accepteert een positief geheel getal van 1 tot 32767. Het moet exact één keer voorkomen vóór de uitvoerbare broncode. PUSH! en POP! accepteren komma-gescheiden scalaire numerieke variabelen.

Waarden worden positioneel hersteld: na PUSH! X,Y,Z zal POP! A,B,C de bewaarde waarden van X, Y en Z respectievelijk toewijzen aan A, B en C. De stack-staat is globaal.

De gegenereerde array is standaard LBLBSTACK#. Met -y/--stack-type kan worden gekozen voor int, single, of double opslag (%, !, of #). Overflow- en underflow-checks worden standaard gegenereerd.

Gestructureerde IF

BAL biedt een blokvorm van IF:

if x=y then!
  print "equal"
endif!

Een optionele ELSE! wordt ondersteund:

if x=y then!
  print "equal"
else!
  print "not equal"
endif!

THEN! moet de laatste tekst op de fysieke bronregel zijn. ELSE! en ENDIF! moeten alleen op hun eigen regel staan. De implementatie gebruikt intern gegenereerde labels en vertakkingen in plaats van de BASIC-expressie te negeren, waardoor BAL geen kennis hoeft te hebben van BASIC-operatorprioriteit.

WHILE / WEND

BAL ondersteunt loops met een test aan het begin:

while! x<10
  print x
  x=x+1
wend!

De expressie na WHILE! wordt ongewijzigd aan BASIC doorgegeven. De loop gaat door zolang de expressie waar is. WEND! moet alleen op zijn eigen regel staan.

DO / LOOP

Een onvoorwaardelijke loop is:

do!
  print x
  x=x+1
loop!

BAL ondersteunt ook vormen met een test aan het einde:

LOOP WHILE

do!
  print x
  x=x+1
loop! while x<10

De loop herhaalt zolang de expressie waar is.

LOOP UNTIL

do!
  print x
  x=x+1
loop! until x>=10

De loop herhaalt totdat de expressie waar is.

EXIT

EXIT! verlaat de binnenste omsluitende WHILE! of DO! loop:

while! x<100
  x=x+1
  if x=50 then!
    exit!
  endif!
wend!

EXIT! kan binnen geneste IF-blokken verschijnen. Het gebruik van EXIT! zonder een omsluitende loop is een fout.

CONTINUE

CONTINUE! springt naar de volgende iteratie van de binnenste omsluitende loop.

Voor een WHILE-loop keert CONTINUE! terug naar de WHILE-conditietest. Voor een DO-loop springt CONTINUE! naar de test aan de onderkant van de loop.

Het gebruik van CONTINUE! buiten een WHILE- of DO-blok is een fout.

Broncode tijdelijk uitschakelen

BAL biedt een mogelijkheid om broncode uit te schakelen, vergelijkbaar met #if 0 in C.

Gebruik: 'OFF! om te stoppen met het genereren van broncode. 'ON! om hiermee te hervatten.

Voorbeeld:

print "before"
'OFF!
print "this code does not exist in the generated program"
goto @missing_label
':temporary
'ON!
print "after"

Alles tussen OFF! en ON! wordt volledig genegeerd: er wordt geen BASIC-output gegenereerd, er worden geen regelnummers toegewezen, labels worden niet gedefinieerd en symbolische referenties worden niet gecontroleerd. OFF! / ON! blokken kunnen genest worden.

Nesting

Gestructureerde constructen gebruiken een blokstack en kunnen genest worden. Sluitende constructen moeten overeenkomen met het actieve blok. Een WEND! die wordt aangetroffen terwijl het actieve blok een IF is, veroorzaakt een fout.

Configureerbare syntaxis

De drie punctuctiekarakters voor BAL-extensies zijn configureerbaar. De standaardwaarden zijn:

  • @: prefix voor symbolische referentie
  • !: suffix voor gestructureerde trefwoorden
  • :: marker voor labeldefinitie

Python-versie opties

De Python-implementatie accepteert lange opties: python3 lblbasic.py --labelchar='%' --structchar='?' --defchar=';' program.bal

Andere opties:

  • -c, --keep-comments: bewaart commentaren (standaard genegeerd).
  • -t, --target-comments: bewaart labeldefinitie-commentaren en maakt labels referenties naar die regels.
  • -L, --keep-label-comments: bewaart labeldefinitie-commentaren zonder ze als vertakkingsdoelen te maken.
  • -n, --dos-newlines: produceert CRLF-regelafbrekingen.
  • -s/--start en -i/--increment: configureert de beginwaarde en stapgrootte van regelnummers.
  • -m, --trim: verwijdert voor- en achterliggende spaties/tabs van elke bronregel.
  • -k, --keep-blanks: bewaart blanke regels als ongenummerde outputregels.

Legacy awk-versie

De awk-implementatie kan deze tekens overschrijven met -v: awk -v labelchar='%' -v structchar='?' -v defchar=';' -f lblbasic.awk program.bal

MBASIC/BAL-versie

In lblbasic.bal / lblbas.bas kunnen de variabelen LC$, SC$ en DC$ aan het begin van het bestand worden aangepast.

Gegenereerde regelnummers

Standaard begint de gegenereerde BASIC bij regel 10 en verhoogt deze met 10. Dit is configureerbaar. Regelnummers zijn beperkt tot het bereik van MBASIC: 0 tot 65529.

Wanneer een toegewezen regelnummer de limiet van 65529 overschrijdt, stopt de implementatie voordat er output wordt geproduceerd.

Waarschuwingen en fouten

Dubbele en niet-gedefinieerde labels

Labels zijn ongevoelig voor hoofd- en kleine letters. Het herhaaldelijk definiëren van hetzelfde label produceert een waarschuwing. Niet-gedefinieerde symbolische referenties worden ongewijzigd gelaten in de output en veroorzaken een waarschuwing, zodat fouten makkelijk te spotten zijn.

Commentaren

BAL herkent zowel traditionele BASIC REM-commentaren als apostrof-commentaren: REM volledige regel commentaar ' volledige regel apostrof commentaar print x ' trailing commentaar

Geciteerde apostrofen zijn geen commentaren. Tekst die lijkt op een label binnen een commentaar wordt niet resolvend gemaakt.

Strings

Geciteerde strings worden behouden. BAL begrijpt dubbele quotes binnen BASIC-strings. Symbolische referenties, apostrofen, colons en gestructureerde tekst binnen strings worden niet geïnterpreteerd als BAL-syntaxis.

Structurele syntaxisfouten

LBLBASIC detecteert structurele problemen, zoals:

  • ELSE! zonder bijbehorende IF
  • Meer dan één ELSE! in dezelfde IF
  • ENDIF!, WEND! of LOOP! zonder bijbehorende start-tag
  • Mismatched blok-nesting
  • EXIT! of CONTINUE! buiten een loop
  • Niet-gesloten OFF!, OPT! of gestructureerde blokken aan het einde van het bestand
  • Ongeldige of conflicterende CONST! definities
  • Een bereikte ERROR! directieve
  • Ongeldige stack-declaraties
  • Regelnummers die de MBASIC-limiet overschrijden

De vier gedistribueerde bestanden

  1. lblbasic.py: De huidige referentie-implementatie. Gebruik Python 3; er zijn geen externe afhankelijkheden.
  2. lblbasic.awk: De oorspronkelijke referentie-implementatie. Nuttig op Unix-achtige systemen en als controle voor de oorspronkelijke functieset. Implementeert geen INCLUDE, CONST, OPT/ENDOPT, ERROR of STACK/PUSH/POP.
  3. lblbasic.bal: LBLBASIC geïmplementeerd in BAL zelf. Dit demonstreert dat BAL bruikbaar is voor niet-triviale programma's.
  4. lblbas.bas: Het reeds geconverteerde MBASIC-programma, klaar voor gebruik onder Microsoft MBASIC op CP/M.

Bootstrap Model

LBLBASIC is ontwikkeld in fasen: lblbasic.py → verwerkt → lblbasic.bal → wordt → lblbas.bas → draait onder → MBASIC → verwerkt → andere .bal programma's.

Dit stelt de ontwikkelaar in staat de taal te ontwikkelen in een moderne omgeving, terwijl er een implementatie beschikbaar blijft die draait op de klassieke BASIC-omgeving die het tool ondersteunt.

Ontwerpprofilosofie

LBLBASIC is niet bedoeld als volledige BASIC-compiler. Het vermijdt bewust het parsen van BASIC-expressies of het implementeren van operatorprioriteit. LBLBASIC behandelt expressies als ondoorzichtige BASIC-tekst en genereert alleen het noodzakelijke control-flow frame. Dit houdt de preprocessor klein genoeg om in MBASIC zelf te implementeren.

Voorbeeldprogramma

':main
x=0
while! x<10
  x=x+1
  if x=3 then!
    continue!
  endif!
  if x=8 then!
    exit!
  endif!
  print x
wend!
do!
  x=x-1
  if x=2 then!
    print "two"
  else!
    print x
  endif!
loop! while x>0
goto @done
'OFF!
':oldcode
print "this entire section is disabled"
goto @missing
'ON!
':done
print "done"
end

Voer dit uit met: python3 lblbasic.py example.bal > example.bas

Bestandsextensies

De aanbevolen conventies zijn:

  • .bal: LBLBASIC-broncode (BAL staat voor BASIC with labels).
  • .bas: Gegenereerde, gewoon BASIC-code.