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
| Functionaliteit | Python | BAL/MBASIC | Legacy awk |
|---|---|---|---|
| Labels en symbolische numerieke substitutie | Ja | Ja | Ja |
| Gestructureerde IF, WHILE, DO, EXIT en CONTINUE | Ja | Ja | Ja |
| OFF/ON onderdrukking en behoud van lege regels | Ja | Ja | Ja |
| Configureerbare brontekens en limieten voor regelnummers | Ja | Ja | Ja |
| INCLUDE bronbestanden | Ja | Ja | Nee |
| CONST numerieke symbolen | Ja | Ja | Nee |
| OPT/ENDOPT, optionele NOT en ERROR | Ja | Ja | Nee |
| Numerieke STACK/PUSH/POP | Ja | Ja | Nee |
| Trim, newline en label-only comment CLI-opties | Ja | Nee | Nee |
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 @foogosub @fooif x then @fooon n goto @one,@two,@threeprint 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/--starten-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 bijbehorendeIF- Meer dan één
ELSE!in dezelfdeIF ENDIF!,WEND!ofLOOP!zonder bijbehorende start-tag- Mismatched blok-nesting
EXIT!ofCONTINUE!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
- lblbasic.py: De huidige referentie-implementatie. Gebruik Python 3; er zijn geen externe afhankelijkheden.
- 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.
- lblbasic.bal: LBLBASIC geïmplementeerd in BAL zelf. Dit demonstreert dat BAL bruikbaar is voor niet-triviale programma's.
- 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.
Groetjes,