Designovervejelser

Det kræver utrolig meget overvejelse at lave sit eget programmerings-sprog fra bunden. Efter vi i projektgrundlaget og problemformuleringen har fundet ud af hvem der skal bruge det, hvordan det skal bruges, og hvad det skal compilere til, kan man gå igang med at overveje, hvilken syntaks det skal have.

I det følgende har vi nedskrevet vores designovervejelser nøje, da vi mener en gennemarbejdet syntaks er nøglen til et let anvendeligt sprog. Beskrivelserne kan med fordel sammenholdes scanneren svendsk.l, da vi de fleste steder skriver det regulære udtryk for det valgte token.

Svendsk er et dansk sprog, og allerede det kan give en del problemer. Er det muligt at bruge æ, ø og å? Skal alle reserverede ord skrives på dansk? Skal decimaler deles med komma, eller med punktum som det er kutyme i lande som USA og England?

mellemrum

[ \t]+


Når et Svendsk-program læses igennem, bliver alle mellemrum ignoreret. Et mellemrum er defineret som værende et almindeligt mellemrums-tegn eller et tabulator-tegn.


ascii_tegn

[^\"\n]


Et ASCII-tegn er defineret som værende alle tegn med undtagelse af anførelses-tegn og det C-kendte newline-tegn, dvs. et backslash efterfulgt af tegnet 'n'.


escape_tegn

\\\"|\\n


Et Escape-tegn er et backslash efterfulgt af enten et anførelses-tegn eller tegnet 'n', jvf. beskrivelsen af ascii_tegn.


lovlig_tekst

\"({ascii_tegn}|{escape_tegn})*\"


En lovlig tekst-streng startes med et anførelses-tegn. Herefter kommer et vilkårligt antal af ascii_tegn eller escape_tegn. Strengen skal afsluttes med endnu et anførelses-tegn.

lovlig_tekst bruges udelukkende i en skriv-sætning.

Eksempler på forekomster af lovlig_tekst kunne være:

"Svendsk: En Svendsk til Java-compiler\n"
"Navnet er \"Svend\"."
"kr.\t200,-\nkr.\t300,-\n"
Se yderligere beskrivelsen af skriv.


bogstav

[A-Za-z]


I Svendsk er et lovligt bogstav et tegn fra A til Z og fra a til z, dvs det er ikke muligt at skrive de danske bogstaver æ, ø og å. Det har vi besluttet, for at undgå de problemer det ville give, med forskellige tegn-tabeller, fx har Windows og DOS ikke den samme tegn-tabel.

  At det kun er A-Z og a-z er dog en sandhed med modifikationer, for i en skriv-sætning er det muligt at skrive en del flere tegn. Læs yderligere beskrivelsen af skriv. Et bogstav bliver ikke i sig selv brugt som et token, men dets definition bruges i fx beskrivelsen af en identifikator (id).


ciffer

[0-9]


Et ciffer er simpelthen bare defineret som et tegn mellem 0 og 9; begge inklusive.


kommentar

";>"([^<]|"<"[^;])*"<;"


Vi kiggede på nogle kendte sprog (C, Pascal og Basic), for at finde en hensigtsmæssig syntaks for kommentarer. Vi bestemte, at en kommentar skal starte med to tegn, da vi mener dette formindsker risikoen for, at man tilfældigt skriver utilsigtede kommentarer. Da vi syntes fint om ';' som det første tegn, var det nærliggende at bruge '>', for at symbolisere at vi starter kommentaren.

En kommentar, der i øvrigt kan strække sig over flere linier, afsluttes med det omvendte, nemlig '<;'. Inspirationen stammer fra sproget C, der henholdsvis bruger '/*' og '*/'.

Det er ikke muligt at have kommentarer inde i kommentarer. Dette ville have været praktisk, hvis man ville udkommentere et stykke kode, der i forvejen var kommenteret. Modsat kan det skabe unødvendig forvirring for programmøren, da han så også skal holde øje med virkefelter (scopes) i sine egne kommentarer.


id (identifikator)

{bogstav}({bogstav}|{ciffer}|_)*


En identifikator skal starte med et stort eller et lille bogstav fra A til Z. Efterfølgende tegn kan være bogstaver (A-Z eller a-z), cifre (0-9) eller understregning (_). Der er ingen begrænsninger på længden af en identifikator.


tal

-?[1-9]{ciffer}*|0


Et tal må ikke starte med tegnet nul (0), medmindre hele tallet er nul. Derudover må der ikke være mere end ét minustegn ('-') i et tal. Efterfølgende tegn skal være cifre mellem 0 og 9.


var_erklaer (Variabelerklæring)

{id}\.({typer})"()"


En erklæring af en variabel består af fire dele: et id, et . (punktum), en type og til sidst () (to parenteser). En variabelerklæring for et heltal i ville derfor se således ud:

  i.heltal()

Det er ikke tilladt at have nogle mellemrum (whitespaces) mellem disse fire dele.
  I vores definition er det ikke muligt at erklære flere variabler, som man ellers kan i Java, ved at skrive:

  int i, j;

Vi mente, det ville være forvirrende for nybegyndere.


Løkke  

I Svendsk skrives løkker på en noget anderledes måde, end det er kendt i andre programmerings-sprog. Som eksempel kan gives en løkke, der lægger tallene fra 1 til 10 sammen i en variabel. Læg specielt mærke til det reserverede ord ITERATION der indeholder det aktuelle gennemløbsnummer (dvs. i nedenstående eksempel er det fra 1 til og med 10):

  a.heltal()

  1{ a = a + ITERATION }10+
Det tilsvarende kode, programmeret i Java, kunne således være:

  int a = 0;

  for(int i=1; i<=10; i++)
    a += i;
eller skrevet mere kompakt:

  int a = 0;

  for(int i=1; i=<10; a += i++) ;
Vi har dog valgt at generere Java-koden v.h.a. en do...while løkke. Dette er udelukkende gjort, for at lette kode-genereringen for os selv, grundet at vi først kender løkkens grænse når vi har læst (og genereret kode til) løkkens 'interne' sætninger.

Java-koden vil derfor komme til at se ud som følgende:

  int a = 0;
  int loop0 = 1;

  do
  {
    a = a + loop0;
    loop++;
  }
  while(loop0 <= 10);
I Svendsk ser et skelet for løkker med grænser således ud:

startværdi
{

  sætning(er)
}
slutværdi
[+|-]

Det skal nævnes, at begge værdier (startværdi og slutværdi) både kan være tal (se beskrivelse andetsteds) og variabler af typen heltal().

Det er også muligt at lave en løkke uden øvre grænse, fx:

  a.heltal()
  1{ a = a + ITERATION }+

Ovenstående løkke vil køre, indtil den specifikt bliver stoppet af en afbryd()-statement. Hvis man vil opnå samme effekt som forrige eksempel, skal løkken derfor udvides med en hvis-sætning:

  a.heltal()
  1{

    a = a + ITERATION
    hvis ( ITERATION = 11)
      afbryd()
  }+
Sidste variant er en løkke uden nedre grænse:

  a.heltal()

  1{ a = a + ITERATION }-

Der er således fire forskellige løkke-strukturer i Svendsk, hvilket nedenstående tabel tydeliggør.


startværdi {

sætning(er)

}slutværdi +

startværdi {

sætning(er)

}slutværdi -

Gentages fra startværdi til slutværdi. Tælleren adderes med en (1) efter hvert gennemløb. Gentages fra startværdi til slutværdi. Tælleren subtraheres med en (1) efter hvert gennemløb.

startværdi {

sætning(er)

}+

startværdi {

sætning(er)

}-

Gentages fra startværdi til uendeligt. Tælleren adderes med en (1) efter hvert gennemløb. Det er kun muligt at springe ud af løkken med en afbryd()-statement. Gentages fra startværdi til uendeligt. Tælleren subtraheres med en (1) efter hvert gennemløb. Det er kun muligt at springe ud af løkken med en afbryd()-statement.
Tabel 5-1: Løkkestrukturer i Svendsk


skriv

skriv(tekst)


skriv-sætningen udskriver en tekst på skærmen. Vi ville gerne have den til at se ud på følgende måde:

  skriv(hvis hundrede piger danser på tyve borde, er der i gennemsnit [100/20] piger på "hvert" bord)

Det har desværre ikke været muligt for os at opnå dette. Problemet var, at vi ikke kunne få FLEX til at forstå, at man er igang med en tekst-streng. Den læste de forskellige ord som identifikatorer. Det skulle samtidigt være muligt at skrive et udtryk i kantede parenteser (i eksemplet er det 100/20) et hvilket som helst sted i teksten. Anførelsestegn (") har desuden ingen speciel betydning.

Vi arbejdede lang tid med problemet, men blev desværre nødt til at ty til en, efter vores mening, mere kedelig version af skriv-sætningen. Samme eksempel kommer derfor til at se således ud i den endelige version:

  skriv("hvis hundrede piger danser på tyve borde, er der i gennemsnit "[100/20]" piger på \"hvert\" bord")

Hvis man skal skrive et udtryk, bliver man først nødt til at afslutte sin tekst-streng med et anførelses tegn. Herefter skrives udtrykket i kantede parenteser, fx [ i = 2 ]. Skal der udskrives mere tekst, skal en ny streng startes med anførelses-tegn. Det er muligt at have et anførelses-tegn i sin tekst-streng, men så skal man først skrive et backslash (\), dvs. man skal skrive \".

Det er også muligt at skrive flere udtryk i én skriv-sætning, men det kræver at der laves kantede parenteser om hvert udtryk:

  skriv([8+2] " = " [8+2] " og " [8+2] " * " [10] " = " [(8+2)*10])

En ny linie indsættes v.h.a. det C-kendte '\n' tegn.

  skriv("Linie 1\nLinie 2\nLinie 3")

Den generede Java-kode bruger System.out.print() til at udskrive teksten på skærmen. Forrige Svendsk-linie bliver derfor oversat til:

  System.out.print("Linie 1\nLinie 2\nLinie 3" + "");

De to sidste anførsels-tegn har ingen betydning for outputtet og er kun medtaget for at lette kode-genereringen.

Se yderligere beskrivelse af tekst-strenge under lovlig_tekst.


Blok

>> sætninger <<


Blokke kan skrives hvor som helst i Svendsk, men bruges normalt kun til at definere en funktions-krop (ikke implementeret), eller hvis man har brug for at skrive mere end en sætning i en hvis-ellers-sætningskonstruktion.

En blok startes med to større-end tegn (>>) og afsluttes med to mindre-end tegn (<<). Grunden til, at vi valgte disse symboler var, at det giver en god fornemmelse af, at efterfølgende kode skal flyttes enten til højre eller venstre (afh. af >> og <<). Brugere af Svendsk har som sagt intet, eller meget lidt, kendskab til programmering, så ved at give dem fornemmelsen af, at en indrykning er nødvendig, håber vi på, at vi samtidigt kan lære dem noget om, at kildekode skal være let-læseligt.

Et eksempel på benyttelse af en blok, kan se sådan ud:

  hvis (SUBeloeb > 2000)
    skriv("Du må være udeboende, da din SU er " [SUBeloeb] " kr.")
  ellers
  >>
    skriv("Du må bo hjemme, da din SU kun er " [SUBeloeb] " kr.")
    hvis (alder > 18)
      skriv(" Det er okay, du er jo også kun " [alder] " år")
    ellers
      skriv(" Det var ikke meget!")
  <<
Vi mener i øvrigt der er stor sammenhæng mellem blokke og kommentarer, da de begge giver indtrykket af noget sammenhængende. Derfor har vi givet dem en syntaks der minder meget om hinanden.


SvendskInput  

Hvis man skal have input fra brugeren, skal man i Java først oprette et objekt af typen BufferedReader. Vi har valgt at erklære dette objekt globalt, da vi ellers kunne komme ud for, at skulle erklære det flere steder i den genererede kode (grundet scopes).

Java-koden for erklæring af objektet:

  java.io.BufferedReader SvendskInput;
  SvendskInput = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));


Det er nu muligt at arbejde på dette objekt hvert gang vi bruger Svendsk-sætningen laes.


Laes

laes(id)


Laes-sætningen læser input fra keyboardet. Et input afsluttes med return. Parameteren til laes, er et id, fx:

  str.streng()
  ...
  laes(str)
Ovenstående Svendsk lægger indtastningerne ind i variablen str.

Den genererede Java-kode bliver:

  try {
    str = SvendskInput.readLine();
  }
  catch(java.io.IOException ioe)
  { str = "";}
SvendskInput er et reserveret ord, der er beskrevet andetsteds.

Det er kun muligt at lægge input i en variabel af typen streng. Andre typer er udeladt grundet tidsmangel.


Sammenligning og Tildeling

=


Vi mener, mange nybegynder har svært ved at skelne mellem, hvilke(t) tegn der skal bruges i en sammenligning og hvilke(t) tegn der skal bruges i en tildeling. I C, skrives fx tal = 2 i tildelinger og tal == 2 i sammenligninger.

Vi har bestemt at bruge det samme tegn (=) i både sammenligninger og tildelinger, da det ud fra kodens kontekst er tydeligt, hvad man mener; fx kan man ikke lave en tildeling i en hvis-sætning.


typer

heltal|boolsk|streng


I Svendsk er der tre typer: heltal, boolsk og streng der henholdsvis svarer til Javas int, boolean og String. Se Definering af sproget Svendsk for yderligere information om disse typer.