NANOL 860409 (c) 1986 by ORD-GROUP 43 NANOL NANOL is een zeer eenvoudige, zelfontworpen, programmeertaal. Toen NANOL werd ontworpen hadden we alleen de beschikking over een BASIC interpreter, een Z80 assembler en een FORTH inter- preter. Het gevolg was dat we bijna alle software in assembler schreven. Het was duidelijk dat we naar een hogere programmeer- taal toe moesten. Het schrijven van een compiler voor een hogere programmeertaal in assembler is echter veel werk. We hebben dan ook NANOL ontwikkeld als een programmeertaal die zeer eenvoudig te compileren is en waarin je eenvoudiger programma's kunt schrijven dan in assembler. Het voornaamste doel bij het ontwikkelen van NANOL was de eenvoud van de compiler. De compiler leest een NANOL file in en vertaalt die naar assembler code. De assembler kan dan de rest verzorgen. Het is ons gelukt om NANOL zo eenvoudig te maken dat de compiler geen symbol-table hoeft bij te houden en zelfs geen getallen hoeft te kunnen converteren van ASCII naar binair. Het centrale principe van de compiler is om de assembler het werk te laten doen. NANOL heeft een paar basisbegrippen: expressie, variabele en functie. Een expressie is een constructie waar een waarde uit komt. Een waarde is een 16 bits unsigned getal. Bijna elke constructie in NANOL is wel een expressie. Een variabele is een geheugenplaats waar je een waarde kunt opslaan. Variabelen moeten worden gedeclareerd. Een functie is een subroutine die een aantal waarden als argu- menten accepteerd en een waarde teruggeeft. Verder is NANOL gebaseerd op een blockstructuur met BEGIN-END paren of haakjes paren. De enige controlestatements zijn een IF- THEN-ELSE-FI en een WHILE-DO-OD. Er is geen GOTO aanwezig maar het blijkt dat dit de programmeur juist forceert om zijn pro- gramma netjes en goed doordacht te schrijven. v.b. van een stuk programma: VAR tmpkwd CO declaratie van de variabele tmpkwd CO PROC kwadraat(tmpkwd)=tmpkwd*tmpkwd CO definitie van de functie kwadraat CO Als op een andere plaats in het programma de constructie 'kwadraat(x)' staat dan vinden de volgende acties plaats: De waarde van expressie x wordt in de variabele tmpkwd gestopt. De subroutine 'kwadra' wordt aangeroepen. (Merk op dat slechts 6 letters significant zijn in de namen.) De subroutine 'kwadra' rekent de waarde van de expressie aan de rechterkant van het = teken in zijn definitie uit. NANOL 860409 (c) 1986 by ORD-GROUP 44 Deze waarde wordt teruggevoerd naar het aanroepende programma- onderdeel. In NANOL zijn er geen beperkingen. De compiler vertaalt elke legale constructie naar assembler. Als men vergeet een variabele te declareren dan merkt de compiler dat niet maar de assembler geeft een error omdat een identifier niet gedeclareerd was. De compiler doet niet aan typechecking. In NANOL bestaat de mogelijkheid om op elk moment een stukje assembler tussen te voegen. Dit is soms nodig om aan speciale eisen te voldoen. (B.v. dat een bepaalde waarde in een bepaald register moet staan bij het aanroepen van het operating systeem.) Bij recursie moet men voorzichtig zijn. Een tweede aanroep van een functie binnen de eerste vernietigd namelijk de inhoud van de argumentvariabelen. In het algemeen kunnen we zegeen dat we erin zijn geslaagd een taal te ontwikkelen die uiterst eenvoudig is en toch een stuk makkelijker programmeert dan assembler. We hebben NANOL gebruikt om een SMALL-C compiler in te schrijven en dit ging zonder grote problemen. Het enige echte probleem was de recursie. Hiervoor hebben we de volgende oplossing gevonden. functie locall(n) : alloceer n locale variabelen op de stack functie locvar(n) : de waarde van locale variabele nummer n functie locass(n,e): stop de waarde van expressie e in locale variabele nummer n. Locall(n) is gewoonlijk het eerste statement in de functie. Locall plaatst een extra returnadres op de stack die naar de dealloceerroutine wijst. Op deze manier is het dealloceren transparant. In het programma ziet het er wat onoverzichtelijk uit, maar het werkt uitstekend.