8. labor: Állapotgépek, sztringek gyakorlás

1 Kommentszűrő

Írj programot, amely a szabványos bemenetről olvas karaktereket fájl vége jelig! A szabványos bemeneten keresztül egy C program érkezik. A program szűrje ki a /* és */ közötti megjegyzéseket a szabványos bemeneten érkező szövegből, és a megjegyzések nélküli szöveget írja a szabványos kimenetre!

  1. Tervezz állapotgépes modellt a feladat megoldására! Készíts állapottáblát és tevékenységtáblát, valamint állapotgráfot! A hallgatók önálló próbálkozása után csoport beszélje meg a megoldást a laborvezetővel!

    Tipp: ha nem megy, nézd meg a 6. heti előadás diáit, az állapotgéphez kapcsolódó részt! A kommentszűrőnek négy állapota lesz: alap, csillagra vár a '/' után, megjegyzésben van, '/'-re vár a '*' után.

  2. A terv alapján írd meg a feladatot megoldó C nyelvű programot! Próbáld ki billentyűzetről!
  3. Mentsd el úgy a programodat, hogy vannak benne /* megjegyzések */ is. Nyiss egy parancssori ablakot, és keresd meg benne a futtathatót (.exe)! Irányítsd át a szabványos bemenetet a második laboron tanult módon úgy, hogy a programod a saját maga forráskódját kapja bemenetként! Ellenőrizd, hogy helyesen eltűnnek-e belőle a megjegyzések! Próbáld ki az átirányítást fájlból fájlba is: a main.c fájlból keletkezzen komment_nelkul.c fájl!

Megoldás

#include <stdio.h>
 
int main() {
    typedef enum Allapot { alap,per,komm,csill } Allapot;
    int c; /* Beolvasott karakter */
    Allapot all = alap; /* Alapállapotról indulunk */
    
    while ((c=getchar())!=EOF) {     /* Fájl végéig olvasunk */
        switch (all) {
            case alap:               /* Ha alapállapotban vagyunk */
                if (c=='/') all=per; /* Jött egy per, lehet komment lesz ezért nem írjuk ki */
                else putchar(c);     /* Egyébként kiírjuk ami jött */
                break;
            case per:                          /* Már jött egy perjel */
                if (c=='*') all=komm;          /* Ha csillag jön, kommentben vagyunk */
                else if (c=='/') putchar('/'); /* Ha mégegy perjel jött,
                                                * akkor az előzőt kiírjuk,
                                                * és maradunk ebben az állapotban */
                else {                         /* Ha valami más jött, akkor kiírjuk
                                                * az előző perjelet, az aktuális karaktert */
                    putchar('/');              /* és visszamegyünk alapállapotba */
                    putchar(c);
                    all=alap;
                }
                break;
            case komm:                 /* Ha kommentben vagyunk */
                if (c=='*') all=csill; /* Csillagot figyeljük és nem írunk ki semmit */
                break;
            case csill:                     /* Ha jött egy csillag a kommentben */
                if (c=='/') all=alap;       /* Perjel esetén vége a kommentnek -> Alapállapot */
                else if (c=='*') all=csill; /* Csillag esetén nincs teendő */
                else all=komm;              /* Egyéb esetben visszamegyünk a komment állapotba */
                break;
        }
    }
    
    /* Ha véget ért a bemenet, elvileg alapállapotban kell lennünk, mert
     * a forráskód nem végződhet bezáratlan kommenttel. Esetleg lehetséges,
     * hogy egy perjel volt a végén, az viszont nem a komment vége, hanem
     * egy osztás: írjuk ki! */
    if (all==per)
        putchar('/');
    return 0;
}

2 A kommentek aránya

Azt mondják, egy szépen megírt program forráskódjának 30%-a megjegyzés. (A missziókritikus programokban, pl. a NASA űrhajót irányító programjában ez sokkal több lehet!) Módosítsd úgy a programodat, hogy a forráskód beolvasása közben meghatározza ezt az arányt is! A kiírás tevékenységek így kiegészülnek a számlálással is.

A most megírt programod hány százaléka komment?

Tipp: tedd el magadnak a most megírt programot. Jól fog jönni a nagy házi feladatod kódja minőségének számszerűsítéséhez. ☺

3 Sztringes feladatok

Lapozz vissza az előző labor feladataira, a 7. héthez. Oldd meg azokat a sztringes feladatokat, amelyekre a múlt órán nem volt idő!

4 További feladatok

Sztringek belseje I.

A négy állapotos C kommentszűrő program nem működik tökéletesen. Ugyanis ez a kód nem tartalmaz kommentet:

printf("/* ez nem komment. */\n");

Javítsd ki úgy az állapotgéped, hogy kezelje ezt is!

Sztringek belseje II.

Hol van vége egy sztringnek? Nem az indító idézőjel utáni következő idézőjel karakternél:

printf("A program azt irja ki, hogy \"Hello, /* nem komment */ vilag\".\n");

Fejleszd tovább az állapotgépet eszerint!

Szöveges fájlok

Írd át a kommentszűró programot úgy, hogy parancssori paraméterként vegye át a forrás- és célfájl nevét! Nyissa meg a fájlokat szöveges módban, és fájlkezelő függvényekkel olvassa és írja a bemenetet és kimenetet! A munka végén ne felejtsd bezárni a fájlokat! A kommentektől megszabadított forráskód a kimeneti fájlba, a kommentek statisztikáját (komment karakterek, összes karakterek, százalék) pedig a szabványos kimenetre írja a program!

A szabványos bemenetről olvasó, kimenetre író getchar() és putchar() függvényeknek van fájlos párja is: ezek neve fgetc() és fputc().

A main függvény paraméterei pedig: int main(int argc, char **argv).

Multifilter

Írd át a kommentszűró programot úgy, hogy ne csak a /* és */ karakterpárokra működjön, hanem tetszőleges karakterpárokra! Pl. a Pascal nyelvben a kommenteket (* és *) karakterekkel is lehetett jelölni. A kezdő- és végpárokat a felhasználó egy konfigurációs fájlban (multifilter.ini) adhassa meg a programnak! A program ellenőrizze, hogy létezik-e a fájl, és ha nem, adjon hibajelzést, majd lépjen ki! (Ha sikerült megnyitnia a fájlt, abban négy karakternek kell lennie; a nyitó kombinációnak, két karakter, és a záró kombinációnak, újabb két karakter. C-hez a fájlban /**/ lenne, Pascalhoz (**).)