Sproget Rascal (v. 2) Til brug i K1 på kurset Oversættere Opdateret 29/11 2004 Abstract Rascal er et simpelt Pascal-lignende imperativt sprog. Dette dokument beskriver uformelt Rascals syntaks og semantik samt en fortolker for Rascal, som kan bruges til at afprøve semantikken. 1 Syntaks Syntaksen for Rascal er vist i figur 1. Grammatikken er tvetydig, så der suppleres med de nedenfor viste præcedensregler. Disse er ikke tilstrækkelige til at sikre entydighed, men i de resterende tilfælde er tvetydigheden (f.eks. associativitet af and) uden betydning for semantikken. Foranstillet minus binder stærkest. mellemstillet plus og minus binder svagere end foranstillet minus, og er begge venstreassociative. then, else, do og while binder stærkere end semikolon. else binder til nærmeste umatchede then. not binder stærkere end and. and binder stærkere end or. 1.1 Leksikalske detaljer Navne (id) starter med et bogstav og kan indeholde bogstaver eller cifre. Kun engelske bogstaver (a z) er tilladt. Der kendes forskel på små og store bogstaver. Navne må ikke være identiske med nøgleord (som er vist i skrivemaskineskrift i figur 1), men må godt indeholde disse. F.eks. er ifald et tilladt variabelnavn. Talkonstanter (num) er ikke-tomme følger af cifrene 0-9. Talkonstanter er begrænset til tal, der kan repræsenteres som 16-bit tokomplement heltal. Kommentarer er afgrænset af krølleparenteser (dvs. { og }). 1
Pgm Decls ; Body. Pgm Body. Decls procedure id ( VarDecls ) ; Body Decls function id ( VarDecls ) : integer; Body Decls Decls ; Decls VarDecls id : Type VarDecls VarDecls ; VarDecls Type integer Type array [ 0.. num ] of integer Body var VarDecls ; Block Body Block Block begin Stats end Stats Stat Stats Stats ; Stats Stat id ( Exps ) Stat LVal := Exp Stat if Cond then Stat Stat if Cond then Stat else Stat Stat while Cond do Stat Stat repeat Stats until Cond Stat read LVal Stat write Exp Stat Block LVal id LVal id [ Exp ] Exp num Exp LVal Exp Exp + Exp Exp Exp Exp Exp Exp Exp id ( Exps ) Exp ( Exp ) Exps Exp Exps Exps, Exps Cond Exp = Exp Cond Exp < Exp Cond Cond and Cond Cond Cond or Cond Cond not Cond Cond ( Cond ) Figure 1: Syntaks for Rascal 2
2 Semantik Hvor intet andet er angivet, er semantikken for de forskellige konstruktioner i sproget identisk med semantikken for tilsvarende konstruktioner i Pascal [1] og lignende sprog (som f.eks. Java eller C). Programmet udføres ved, at den Body, som er erklæret på topniveau udføres. Rascal arbejder med følgende typer: 32-bit tokomplement heltal har typen integer. Endimensionale tabeller af heltal har typen array[0..n] of integer, hvor n er en heltalskonstant, der angiver indeks på sidste element i tabellen. Tabeller er stakallokerede, dvs. at de forsvinder, når den funktion eller procedure i hvilken de er erklærede er færdigudført. Boolske værdier har ikke noget typenavn, da de ikke kan være værdier af udtryk eller variabler. De findes kun i betingelser, som er en særskilt syntaktisk kategori. Oversigt over operatorer: : erklærer variabelen, funktionen eller parameteren til venstre for kolonet til at have den på højre side angivne type. For funktioner, er det returtypen, der erklæres. + og - opererer på heltal. - findes både som foranstillet og mellemstillet operator. Semantikken er den sædvanlige. := er en tildelingsoperator. Venstresiden er en L-værdi, som angiver enten en variabel eller et element i en tabel. Værdien af højresiden udregnes og lægges i den plads, som venstresiden angiver. = afgør om det venstre argument er lig med det højre. Kan kun bruges på heltal. < afgør om det venstre argument er mindre end det højre. Kan kun bruges på heltal. and, or og not er de sædvanlige logiske operatorer. and og or beregner altid begge argumenter, og er følgelig ikke sekventielle logiske operatorer. Andre konstruktioner: Funktions- eller procedureerklæringer består af en angivelse af parameterenes navne og typer efterfulgt af en Body, der bliver udført som led i et kald til funktionen. Funktionserklæringer angiver endvidere returtypen, der altid er integer. En funktion eller procedure kan kalde sig selv og alle tidligere erklærede funktioner eller procedurer. I kroppen af en funktion er funtionens navn også navnet på en lokal variabel af type heltal. Det er denne 3
variabels værdi, der returneres ved funktionens afslutning. Det er udefineret, hvad resultatet er, hvis denne variabel ikke tildeles en værdi inden funktionen returnerer. Procedurekroppe (Body) består af variabelerklæringer efterfulgt af en blok (eller bare en blok alene). De erklærede variabler er kun tilgængelige i den tilhørende blok. if c then s 1 else s 2 beregner betingelsen c. Hvis c er sand, udføres s 1, ellers udføres s 2. if c then s beregner betingelsen c. Hvis c er sand, udføres e, ellers intet. while c do s beregner betingelsen c. Hvis c er sand, udføres s og hele while-dosætningen gentages. Hvis betingelsen c er falsk stopper løkken uden yderligere beregning. repeat s until c udfører først s og beregner siden betingelsen c. Hvis c er falsk, gentages hele repeat-until-sætningen. Hvis betingelsen c er sand stopper løkken. Funktions- og procedurekald skrives som et funktionsnavn eller procedurenavn med argumenterne anført i parentes og adskilt af kommaer. De aktuelle parametre i kaldet skal have samme type som de erklærede formelle parametre til funktionen eller proceduren. Parametrene beregnes fra venstre mod højre inden kaldet foretages. Et procedurekald er en sætning (Stat) og et funktionskald er et udtryk (Exp). Man må ikke bruge en funktion som procedure eller omvendt. read indlæser et heltal og lægger det i den angivne variabel eller tabelelement. write udskriver det heltal, som det angivne udtryk beregner. Diverse kommentarer: Operander til mellemstillede operatorer beregnes fra venstre til højre. Funktioner og procedurer har samme navnerum, men variabler har navnerum separat fra disse, se dog ovenfor om returvariablen i en funktion. En senere erklæring af funktion eller procedure med navn som en tidligere overskygger denne tidligere erklæring. Der må ikke være to parametre med samme navn i samme parameterliste eller samme variabelerklæringsliste (i en Body). 4
Hvis en variabel i en variabelerklæringsliste har samme navn som en parameter i den procedure eller funktion, hvor den forekommer, så overskygger variabelerklæringen parametererklæringen. Den variabel, der angiver returværdien af en funktion, overskygger en parameter af samme navn men bliver overskygget af en variabel af samme navn. Et udtryk kan godt have en tabel som værdi. Det eneste udtryk, der kan have en tabel som værdi er en variabel, da ingen operatorer returnerer tabeller og alle funktioner returnerer heltal. Man kan ikke tildele en ny værdi til en tabelvariabel, kun til de enkelte elementer. Så den eneste sted man kan bruge et udtryk med tabelværdi er som parameter til en funktion eller procedure. Det er pegepinden til tabellen, der overføres og ikke hele indholdet. Dermed adskiller Rascal sig fra Pascal standarden. 1 3 Abstrakt syntaks og fortolker Filen Rascal.sml angiver datastrukturer for den abstrakte syntaks for programmer i Rascal. Hele programmet har type Rascal.Prog. Filen Main.sml indeholder et program, der kan indlæse, typechecke og køre et Rascal program. Det kaldes ved at angive filnavnet for programmet på kommandolinien. Når programmet er indlæst og typechecket, indlæses inddata fra standard input og resultater skrives på standard output. Main.sml findes i en oversat udgave kaldet RunRascal. Selv om sproget Rascal er defineret til at bruge 32-bit heltal bruger fortolkeren af tekniske årsager 31-bit tal. Bortset fra denne detalje kan fortolkeren bruges til at afklare spørgsmål om Rascals semantik. Inddata til fortolkeren RunRascal skal være på separate linier. Hvis der er to eller flere inddatatal på samme linie, læses kun det første. Læg mærke til at fortolkeren bruger bufferet output, så den ikke udskriver noget, før bufferen er fuld eller programmet slutter. Der er givet en række fejltestprogrammer skrevet i Rascal. Filerne errornn.r (hvor NN løber fra 00 til 18) er forskellige programmer med typefejl og lignende vederstyggeligheder. Disse kan bruges til at teste typecheckeren (dog giver de ikke fuldstændig test). Derudover findes følgende Rascal-programmer: test0.r indlæser og udskriver tal indtil et 0 er læst. test1.r indlæser tal n og udskriver n + 1 indtil n = 0 er læst. test2.r Tester virkefelt af procedurer. test3.r Tester tildeling af arrays. 1 hvor man skal angive var i parametererklæringen for at få denne opførsel. 5
test4.r Tester boolske operatorer. fib.r indlæser et tal n og udskriver det n te Fibonaccital fac.r indlæser et tal n og udskriver n! (n fakultet). primes.r indlæser et tal n (hvor n 1000) og udskriver alle primtal under n. quicksort.r indlæser et tal n samt n tal (hvor n 1000). Disse udskrives derefter i sorteret rækkefølge. Til hvert af de ovenstående programmer findes filer med inddata, der er passende til afprøvning. De ligger i filerne program.in, hvor program.r er det tilhørende Rascal program. Flere testprogrammer kan komme i forbindelse med opgaverne i K1-2. References [1] Pascal language tutorial, http://www.geocities.com/hotdogcom/ptutor/paslist.html 6