T-79.148 yky 2003 Tietojenkäittelyteorian peruteet Harjoitu 7 Demontraatiotehtävien ratkaiut 4. Tehtävä: Ooita, että yhteydettömien kielten luokka on uljettu yhdite-, katenaatioja ulkeumaoperaatioiden uhteen, o. jo kielet L 1, L 2 Σ ovat yhteydettömiä, niin amoin ovat myö kielet L 1 L 2, L 1 L 2 ja L 1. Vatau: Olkoon L 1 ja L 2 yhteydettömiä kieliä. Määritellään nyt kieliopit G 1 = (V 1, Σ 1, R 1, 1 ) ja G 2 = (V 2, Σ 2, R 2, 2 ), iten, että L(G 1 ) = L 1 ja L(G 2 ) = L 2. Vaaditaan liäki, että (V 1 Σ 1 ) (V 2 Σ 2 ) =, eli kieliopeia ei eiinny amoja välikkeitä. Koka kieliopin välikkeet voidaan tarvittaea nimetä uudelleen, ei tämä aeta oleellita rajoituta. 5. Tehtävä: Unioni: Olkoon uui välike ja G = (V 1 V 2, Σ 1 Σ 2, R 1 R 2 1 2,. Nyt L(G) = L(G 1 ) L(G 2 ) = L 1 L 2. Näin on, koka :tä voidaan johtaa vain 1 tai 2, joita voidaan edelleen johtaa vain anoja jotka kuuluvat jompaan kumpaan aiemmita kielitä (ääntöjen ekaannukelta vältytään, koka välikejoukot ovat pitevieraita). Katenaatio: Tällä kertaa uui kielioppi G = (V 1 V 2, Σ 1 Σ 2, R 1 R 2 1 2,. Nyt L(G) = L 1 L 2. Kleenen tähti: Tällä kertaa uui kielioppi G = (V 1, Σ 1, R 1 ɛ 1,. Nyt L(G) = L 1 (a) Ooita, että euraava yhteydetön kielioppi on monielitteinen: ele. (b) Muodota (a)-kohdan kieliopin kana ekvivalentti, o. aman kielen tuottava ykielitteinen kielioppi. Vatau: Yhteydetön kielioppi G on monielitteinen, mikäli on olemaa ana w L(G) iten, että w:llä on ainakin kaki erilaita jäennypuuta. Tehtävän kieliopille ykinkertaiin tällainen ana on: if b then if b then ele, joka voidaan jäentää euraavati: ele 1
ele Yleenä ohjelmointikieliä halutaan ele-laue liittää lähinpään mahdollieen if-laueeeen. Ylläolevita puita enimmäinen vataa tätä käytäntöä. Määritellään kielioppi euraavati: G = (V, Σ, P, ) V =, B, U,, b, if, then, ele Σ =, b, if, then, ele P = B U B if b then B ele B U if b then B ele U Tää välikeellä B aadaan johdettua vain ohjelmia, joia kaikilla if-laueilla on ekä then- että ele-haarat. Välikkeellä U johdetaan itten if-laueet, joita puuttuu elehaara. 6. Tehtävä:Laadi rekuriivieti etenevä jäentäjä edelliten harjoituten tehtävän 6 kieliopille. Vatau: Alla oleva C-ohjelma toteuttaa rekuriivien jäentäjän kieliopille: C ; C a begin C end for n time do Tää on ykinkertaitettu hieman edellien lakuharjoitukerran 6. tehtävän kielioppia korvaamalla erilliet numerot terminaalilla n, joka tarkoittaa mitä tahana numeroa. Tärkeimmät ohjelmaa eiintyvät funktiot ovat: C(), () toteuttavat kieliopin varinaiet äännöt lex() lukee yötteetä euraavan lekeemin ja tallettaa en globaaliin muuttujaan current tok. expect(int token) yrittää lukea yötteetä lekeemin token. Mikäli lukeminen epäonnituu annetaan virheilmoitu. conume token() merkitään tämänhetkinen lekeemi käytetyki. Tämä (tai jokin muu vataava funktio) tarvitaan iki, että joiain tapaukia täytyy yötettä lukea yki lekeemi eteenpäin ennen kuin tiedetään, mitä ääntöä täytyy käyttää. Käytännöä ohjelmointikielten jäentäjät toteutetaan yleenä käyttäen lex- ja yacc-työkaluja 1. Näitä lex muodotaa tilakonepohjaien elaajan, joka tunnitaa äännölliillä lauekkeilla määritellyt lekeemit, ja yacc tekee pinoautomaattipohjaien jäentimen annetulle yhteydettömälle kieliopille. 1 Tai niiden johdannaiia. 2
#include <tdio.h> #include <tdlib.h> #include <ctype.h> /* Define the alphabet */ enum TOKEN DO, FOR, END, BEGIN, TIME, OP, C, NUMBER, ERROR ; cont char* token[] = "do", "for", "end", "begin", "time", "a", ";", "NUMBER", NULL ; /* A global variable holding the current token */ int current_tok = ERROR; /* Maximum length of a token */ #define TOKEN_LEN 128 /* declare function correponding to nonterminal */ void (void); void C(void); int lex(void); void conume_token(void); void error(char *t); void expect(int token); void C(void) (); lex(); if (current_tok == C) printf("c => ; C\n"); ele printf("c => \n"); void (void) lex(); witch (current_tok) cae OP: printf(" => a\n"); cae BEGIN: expect(end); printf(" => begin C end\n"); cae FOR: expect(number); 3
expect(time); expect(do); (); printf(" => for N time do \n"); default: error("pare error"); /* int lex(void) return the next token of the input. */ int lex(void) tatic char token_text[token_len]; int po = 0, c, i, next_token = ERROR; /* I there an exiting token already? */ if (current_tok!= ERROR) return current_tok; /* kip whitepace */ do while (c!= EOF && ipace(c)); if (c!= EOF) ungetc(c, tdin); /* read token */ while (c!= EOF && c!= ; &&!ipace(c) && po < TOKEN_LEN) token_text[po++] = c; if (c == ; ) if (po == 0) /* emicolon a token */ next_token = C; ele /* trailing emicolon, leave it for future */ ungetc( ;, tdin); token_text[po] = \0 ; /* trailing zero */ /* identify token */ if (idigit(token_text[0])) /* number? */ next_token = NUMBER; ele /* not a number */ for (i = DO; i < NUMBER; i++) if (!trcmp(token[i], token_text)) next_token = i; current_tok = next_token; return next_token; 4
void conume_token(void) current_tok = ERROR; void error(char *t) printf(t); exit(1); /* try to read a token from input */ void expect(int token) int next_tok = lex(); if (next_tok == token) return; ele error("pare error"); int main(void) int i; return 0; 5