A1. Comentarii C Completați automatul dat în program (redat și mai jos) cu stări și tranziții astfel încât să urmărească ambele tipuri de comentarii din C. Desenați automatul rezultat.
type state = In Out Slash (* de completat cu alte stări *) let delta = function (* function: state -> char -> state *) In -> (function '\n' -> Out _ -> In) Out -> (function '/' -> Slash _ -> Out) Slash -> (function '/' -> In _ -> Out) let rec fold_input state = (* ca fold_left, pe șirul caracterelor citite *) try let c = input_char stdin in (* încearcă să citească un caracter c *) fold_input (delta state c) (* aplică din nou pe starea următoare *) with _ -> state (* excepție la citire: returnează starea curentă *) (* starea acceptoare e Out: programul se termină afară din comentariu *) let _ = print_endline (if fold_input Out = Out then "OK" else "ends in comment")Starea inițială e Out (automatul nu a citit nimic, deci nu a început niciun comentariu). Funcția de tranziție a automatului e delta.
#include <stdio.h> typedef enum { OUT, SLASH, IN } state_t; char *name[] = { "out", "slash", "in" }; state_t delta(state_t state, int c) // funcția de tranziție { switch(state) { // doar pentru comentariile cu // default: // nu va ajunge aici, sunt doar 3 valori posibile case OUT: return c == '/' ? SLASH : OUT; case SLASH: return c == '/' ? IN : OUT; case IN: return c == '\n' ? OUT : IN; } } int main(void) // comentariu până la sfârșit de linie { state_t state = OUT; for (int c; (c = getchar()) != EOF; ) state = delta(state, c); printf("end state: %s\n", name[state]); }Compilați programul din terminal cu comanda ocamlc comment1.ml, respectiv gcc comment1.c.
A2. Automate și traductoare Modificați funcția de tranziție de mai sus
astfel încât automatul să scrie la ieșire tot textul în afara comentariilor.
Funcția delta va returna mai departe aceleași valori; tipărirea se face înainte de a preciza valoarea returnată, folosind secvențierea cu ; a evaluării expresiilor.
A3. Simboluri consecutive
Implementați în program (C sau ML) automatul de la temă (va recunoaște sau nu un șir citit de la intrare, până la linie nouă).
Dacă scrieți programul în C, puteți implementa funcția de tranziție și ca matrice, indexată după stare și simbol de intrare.
R1. Exemple comune Scrieți expresii regulate și/sau automate pentru următoarele noțiuni:
type regexp = Void Eps Sym of char Alt of regexp * regexp (* alternativa, reuniune *) Seq of regexp * regexp (* secventiere, concatenare *) Rep of regexp (* inchidere Kleene=repetitie *)Aveți dat și un program care citește o expresie regulată, folosind notația | (nu +) pentru reuniune/alternativă.
R2. Șirul vid Scrieți o funcție care determină dacă o expresie regulată poate genera șirul vid.
R3. Primul caracter
Scrieți o funcție care ia ca parametru o expresie regulată și returnează mulțimea tuturor caracterelor care pot fi primele într-un șir generat de acea expresie regulată.
Cazul cel mai interesant e al concatenării, când primul caracter poate
proveni din prima expresie, sau din a doua, dacă prima expresie poate genera șirul vid (limbajul reprezentat de expresie conține limbajul vid). Folosiți pentru aceasta funcția de la punctul anterior.
R4. Ultimul caracter Scrieți o funcție care ia ca parametru o expresie regulată și returnează mulțimea tuturor caracterelor care pot fi ultimele într-un șir generat de acea expresie regulată.
R5. Expresia acceptă șirul? Pentru a determina pas cu pas dacă un șir poate fi generat de o anumită expresie regulată, adaptăm testul pentru primul caracter de la problema 3.
Determinăm expresia regulată care reprezintă toate continuările posibile după primul simbol a în expresia re dată. Aceasta se numește derivata expresiei regulate re în raport cu simbolul a.
Altfel spus, deriv(re, a) e expresia regulată reprezentând toate șirurile w astfel încât șirul aw e generat de expresia inițială.
Apelați apoi repetat funcția pentru a determina dacă o expresie regulată acceptă un șir dat. Folosiți liste de caractere sau modulul String pentru lucrul cu șiruri.