• Keine Ergebnisse gefunden

expr ::= term | term + expr | term − expr term ::= f actor | f actor ∗ term | f actor/term f actor ::= (expr) | NU M | ID

N/A
N/A
Protected

Academic year: 2022

Aktie "expr ::= term | term + expr | term − expr term ::= f actor | f actor ∗ term | f actor/term f actor ::= (expr) | NU M | ID"

Copied!
6
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Universität Mannheim

Lehrstuhl für Praktische Informatik IV Prof. Dr. W. Effelsberg

Christoph Kuhmünch, Gerald Kühne

Praktische Informatik II SS 2000

Übungsblatt 10 Ausgabe: Mi, 18.07.00 Abgabe: Di, 26.07.00 Aufgabe 1: Parsing [10 Punkte]

Gegeben ist folgende Grammatik für einfache arithmetische Ausdrücke in Infixnotation:

expr ::= term | term + expr | termexpr term ::= f actor | f actorterm | f actor/term f actor ::= (expr) | NU M | ID

NU M ::=

0

0

0

| .. |

0

9

0

ID ::=

0

a

0

| .. |

0

z

0

Dabei ist expr das Startsymbol. Als Beispiel dient der Ausdruck 5a + b + c/(d + 3) (a) [4 Punkte] Zeichnen Sie den Parsetree.

NUM

ID ID

ID

NUM ID

+

/ +

+

*

( )

expr

term expr

factor term

factor

term expr

factor term

term factor

factor expr

term expr

factor term

factor w(d)

w(3) w(+)

w(*)

w(5) w(a) w(b)

w(c)

w(/)

(b) [1 Punkt] Ist die Grammatik eindeutig?

Ja, weil eindeutig feststeht, welches Terminal- / Nicht-Terminal-Symbol als “nächstes” zu verwenden ist.

(c) [2 Punkte] Ergänzen Sie den Parsetree um semantische Aktionen zur Erzeugung eines Postfix–Ausdrucks. Wie sieht der von ihrem Parsetree erzeugte Postfix–Ausdruck aus?

Zunächst wird an jedes Terminalzeichen ein "’write"’-Befehl angehängt. Im Baum werden

dann zuerst der linke, dann der rechte Zweig und zuletzt der Knoten selbst ausgegeben

(siehe rote Markierung in der Abbildung oben).

(2)

Postfix–Ausdruck: 5abcd3 + / + +

(d) [3 Punkte] Zu dieser Grammatik soll nun ein Parser in C entwickelt werden. Da die Symbole nur ein Zeichen lang sind, ist keine lexikalische Analyse notwendig. Als Ausgabe soll ein äquivalenter Ausdruck in Postfix-Form generiert werden.

#include<stdio.h>

#include<stdlib.h>

/*

Uebungsblatt 10, Aufgabe 1d)

Umwandeln von arithmetischen Ausdruecken (Infixnotation -> Postfixnotation) Grammatik siehe Uebungsblatt 10

HINWEISE: - Die Eingabe erfolgt ueber die Standardeingabe - Es sind keine Leerzeichen in der Eingabe erlaubt

*/

/* Vorwaertsdeklarationen */

void error(char* message);

void print(char c);

void expr(FILE* input);

void term(FILE* input);

void factor(FILE* input);

int NUM(char);

int ID(char);

void error(char* message) {

fprintf(stderr,"\nFehler: %s\n", message);

exit(1);

}

void print(char c) {

putchar(c);

}

/* expr ::= term | term + expr | term - expr */

void expr(FILE* input) {

char c;

term(input); /* am Anfang steht immer ein term */

c = getc(input); /* Folgezeichen einlesen */

if (c == ’+’ || c == ’-’) {

expr(input); /* bei + oder - rekursiver Aufruf */

print(c); /* Operator (+ oder -) ausgeben */

} else {

ungetc(c, input); /* ansonsten Zeichen zurueck in den Eingabe- strom */

} }

(3)

/* term ::= factor | factor * term | factor / term */

void term(FILE* input) {

char c;

factor(input); /* am Anfang steht immer ein factor */

c = getc(input); /* Folgezeichen einlesen */

if (c == ’*’ || c == ’/’) {

term(input); /* bei * oder / rekursiver Aufruf */

print(c); /* Operator (* oder /) ausgeben */

} else {

ungetc(c, input); /* ansonsten Zeichen zurueck in den Eingabe- strom */

} }

/* factor ::= (expr) | NUM | ID */

void factor(FILE* input) {

char c;

c = getc(input); /* Folgezeichen einlesen */

if (c == ’(’) { /* ist es ein Klammerausdruck? */

expr(input); /* ja => Ausdruck auswerten */

if (getc(input) != ’)’) { /* auf schliessende Klammer pruefen */

error("’)’ erwartet");

}

} else if (NUM(c) || ID(c)) { /* es muss eine Zahl oder ein Identifier */

print(c); /* angegegeben werden */

} else {

error ("Zahl (0..9) oder Identifier (a..z) erwartet");

} }

/* NUM ::= ’0’ | .. | ’9’ */

int NUM(char c) {

return (c >= ’0’ && c <= ’9’);

}

/* ID ::= ’a’ | .. | ’z’ */

int ID(char c) {

return (c >= ’a’ && c <= ’z’);

}

int main() {

char c;

FILE* input = stdin; /* Standardeingabe verwenden */

printf ("Infix -> Postfix\n");

(4)

printf ("Ausdruck eingeben (ohne Leerzeichen): ");

expr(input); /* Ausdruck auswerten */

if(getc(input) != ’\n’) /* sind alle Zeichen bearbeitet? */

error ("Ungueltiges Zeichen in der Eingabe");

return 0;

}

Aufgabe 2: Codeerzeugung [10 Punkte]

Der Parser aus Aufgabe 2d) soll nun so modifiziert werden, daß er Code für den 68000- Assembler erzeugt. Die arithmetischen Ausdrücke sollen allerdings keine Variablen mehr en- thalten (d.h. es sind nur noch Ziffernkonstanten zulässig). Ändern Sie die Ausgaberoutine aus Aufgabe 2d) entsprechend ab.

#include<stdio.h>

#include<stdlib.h>

/*

Uebungsblatt 10, Aufgabe 2)

Umwandeln von arithmetischen Ausdruecken in 68000-Assembler Grammatik siehe Uebungsblatt 10

ANALOG ZU Aufgabe 1d):

- Es wird eine andere print-Routine verwendet - In der main-Routine wurde ein printf hinzugefuegt HINWEISE: - Die Eingabe erfolgt ueber die Standardeingabe

- Es sind keine Leerzeichen in der Eingabe erlaubt

- Im Gegensatz zur Aufgabe 1d) sind keine Identifier (a..z) erlaubt

*/

/* Vorwaertsdeklarationen */

void error(char* message);

void print(char c);

void expr(FILE* input);

void term(FILE* input);

void factor(FILE* input);

int NUM(char);

int ID(char);

void error(char* message) {

fprintf(stderr,"\nFehler: %s\n", message);

exit(1);

}

void print(char c) {

switch (c) {

case ’+’: /* arithmetische Operationen */

case ’-’:

(5)

case ’*’:

case ’/’:

printf ("move (SP)+,D1\n"); /* Operanden vom Stack holen */

printf ("move (SP)+,D0\n");

switch (c) { /* Operation ausfuehren */

case ’+’:

printf ("add D1,D0\n");

break;

case ’-’:

printf ("sub D1,D0\n");

break;

case ’*’:

printf ("muls D1,D0\n");

break;

case ’/’:

printf ("divs D1,D0\n");

break;

}

printf ("move D0,-(SP)\n"); /* Ergebnis auf den Stack legen */

break;

default: /* Werte */

if (c >= ’0’ && c <= ’9’) {

printf ("move #%c,-(SP)\n",c);

} else {

error ("Ungueltiges Zeichen");

} } }

/* expr ::= term | term + expr | term - expr */

void expr(FILE* input) {

char c;

term(input); /* am Anfang steht immer ein term */

c = getc(input); /* Folgezeichen einlesen */

if (c == ’+’ || c == ’-’) {

expr(input); /* bei + oder - rekursiver Aufruf */

print(c); /* Operator (+ oder -) ausgeben */

} else {

ungetc(c, input); /* ansonsten Zeichen zurueck in den Eingabe- strom */

} }

/* term ::= factor | factor * term | factor / term */

void term(FILE* input) {

char c;

factor(input); /* am Anfang steht immer ein factor */

c = getc(input); /* Folgezeichen einlesen */

if (c == ’*’ || c == ’/’) {

term(input); /* bei * oder / rekursiver Aufruf */

print(c); /* Operator (* oder /) ausgeben */

} else {

ungetc(c, input); /* ansonsten Zeichen zurueck in den Eingabe-

(6)

strom */

} }

/* factor ::= (expr) | NUM | ID */

void factor(FILE* input) {

char c;

c = getc(input); /* Folgezeichen einlesen */

if (c == ’(’) { /* ist es ein Klammerausdruck? */

expr(input); /* ja => Ausdruck auswerten */

if (getc(input) != ’)’) { /* auf schliessende Klammer pruefen */

error("’)’ erwartet");

}

} else if (NUM(c) || ID(c)) { /* es muss eine Zahl oder ein Identifier */

print(c); /* angegegeben werden */

} else {

error ("Zahl (0..9) oder Identifier (a..z) erwartet");

} }

/* NUM ::= ’0’ | .. | ’9’ */

int NUM(char c) {

return (c >= ’0’ && c <= ’9’);

}

/* ID ::= ’a’ | .. | ’z’ */

int ID(char c) {

return (c >= ’a’ && c <= ’z’);

}

int main() {

char c;

FILE* input = stdin; /* Standardeingabe verwenden */

printf ("Infix -> 68000\n");

printf ("Ausdruck eingeben (ohne Leerzeichen): ");

expr(input); /* Ausdruck auswerten */

printf ("move (SP)+,D0\n"); /* Endergebnis nach D0 laden */

if(getc(input) != ’\n’) /* sind alle Zeichen bearbeitet? */

error ("Ungueltiges Zeichen in der Eingabe");

return 0;

}

Referenzen

ÄHNLICHE DOKUMENTE

Extend INTEGER by a function absolute with the properties of the absolute value function on Z.. Show that this is an enrichment

Although any treewalk can be accomplished easily with un- parse rules, their original purpose (and origin of their name) is to reverse the process of parsing terms into syntax trees

Recent theoretical work has added to the list by connecting R&amp;D activities characterized by economies of scope and knowledge spillovers -- those that are likely to have

hewever, the key should not be activated until after the terminal leaves Receive mode.' I£nGt turnec.r sff by the eperator; the Error light will be reset·at

Kann eine dieser Variablen mit der andere berechnet werden, so wird der „Rechnungsweg“ (was wir eben im Kopf rechnen…) als mathematischer Term notiert.. Man kann den Term auch

Epidemics in social contact networks and superspreading Franziska Lam (Mobi), Jeanine Wippermann, Marco Wolf 15.00-15.45. Predicting

Induration of sediment as a function of burial depth in pelagic sediments (Swedish Deep-Sea Expedition, East Pacific, N. Pacific basin) and in rapidly accumulating clay sediments

To do so, the dynamics of the short rate is specified as a non-parametric diffusion, whose drift and volatility are estimated using the method developed by Jiang and Knight (1997).