Analizator leksykalny z wykorzystaniem leksera

0

Muszę przygotować z wykorzystaniem lex-a analizator leksykalny rozpoznający poprawnie zapisane daty w różnych formatach.

Wejście: Dzis jest 20.04.2020 jutro bedzie 21-4-2020, ciekawe za ile dni skonczy sie kwarantanna moze 12/05/2020 a co sie stanie jak potrwa do 01-czerwiec-2020 oby nie bo chcialbym zaplanowac wakacje od 1-7-2020.

Wyjscie: Dzis jest 20-kwiecien-20 jutro bedzie 21-kwiecien-20, ciekawe za ile dni skonczy sie kwarantanna moze 12-maj-20 a co sie stanie jak potrwa do 01-czerwiec-20 oby nie bo chcialbym zaplanowac wakacje od 01-lipiec-20.

Nie mam kompletnie pojęcia jak się do tego zabrać, czy mogę liczyć na jakieś wskazówki ? Nigdy wcześniej nie pisałem nic w C

0
mikko napisał(a):

Nigdy wcześniej nie pisałem nic w C

Projekt na 1-3 tys linii ? I to niebanalny. Masz szanse?

btw musisz użyć Lex'a i C? Dla mnie to średniowiecze, m.in. jest nieanalizowany wzrokowo. Wolę Antlr.

0
ZrobieDobrze napisał(a):
mikko napisał(a):

Nigdy wcześniej nie pisałem nic w C

Projekt na 1-3 tys linii ? I to niebanalny. Masz szanse?

btw musisz użyć Lex'a i C? Dla mnie to średniowiecze, m.in. jest nieanalizowany wzrokowo. Wolę Antlr.

Według mojego wykładowcy to powinno być około 60 linijek, tak niestety Lex i czyste C jest wymogiem, Lex'a ani C nie mieliśmy ani nie widzieliśmy na żadnych zajęciach, także nawet ciężko było mi ocenić skomplikowanie tego zadania. Nie da się tego krócej napisać, wykładowca udostępnił krótki kod, powiedział że tylko w 2 linijkach wystarczy zmienić aby robił to czego on wymaga

0
ZrobieDobrze napisał(a):

btw musisz użyć Lex'a i C? Dla mnie to średniowiecze, m.in. jest nieanalizowany wzrokowo. Wolę Antlr.

Antlr gdy nie trzeba Yacc/Bison to trochę przerost formy nad treścią. A Lex/Flex z tego co pamietam wspiera wyrażenia regularne wiec może można by to ogarnąć jednym wyrażeniem regularnym za bezczela :P

Nie da się tego krócej napisać, wykładowca udostępnił krótki kod, powiedział że tylko w 2 linijkach wystarczy zmienić aby robił to czego on wymaga

To daj ten kod to zmienimy

0

na 99% o tym kodzie tak mówił:

%{
#include 
using namespace std;
int liczba;
%}

digit [0-9]
digits {digit}+
fractional "."{digits}
sign_opt ("+"|"-")?
exp_opt ((e|E){sign_opt}{digits})?
number {sign_opt}({digits}{fractional}|{digits}"."?|{fractional}){exp_opt}   //teorytycznie wskazał tą linię

%%

{number} { cout << atof(yytext) << ", "; liczba++; }                        // oraz tą

.|\n { /* nothing */ }

%%

int main() {
   liczba = 0;
   cout << "Poczatek skanowania..." << endl;
   yylex();
   cout << endl << "Koniec skanowania, zeskanowano liczb: " << liczba << endl;
   return 0;
}

Na pozostały jeden procent o tym:

%{
#include <stdio.h> 
#include <stdlib.h>

int numOperators = 0;
int numInts = 0;
int numDoubles = 0;
int numBrackets = 0;
int intValue = 0;
double doubleValue = 0.0;

%}

digit [0-9]
hex_digit {digit}|[a-f]|[A-F]
digits {digit}+
hex_digits {hex_digit}+
hex_pref "0x"|"0X"
fractional "."{digits}
sign_opt ("-")?
exp_opt ((e|E){sign_opt}{digits})?
plus_op "+"
minus_op "-"
mult_op "*"
div_op "/"
operator {plus_op}|{minus_op}|{mult_op}|{div_op}
op_bracket "("
cl_bracket ")"
dec_num {digits}
hex_num {hex_pref}{hex_digits}
double_num ({digits}{fractional}|{digits}"."?|{fractional})
double_exp_num ({digits}{fractional}|{digits}"."?|{fractional}){exp_opt}

%%

{dec_num} {	printf("liczba dziesietna (%s)\n",yytext);
		++numInts;
		intValue += strtol(yytext,NULL,10); }

{hex_num} {	printf("liczba szesnastkowa (%s)\n",yytext);
		++numInts;
		intValue += strtol(yytext,NULL,16); }

{double_num} {	printf("liczba rzeczywista (standardowa) (%s)\n",yytext);
		++numDoubles;
		doubleValue += strtod(yytext,NULL); }

{double_exp_num} { printf("liczba rzeczywista (wykładnicza) (%s)\n)",yytext);
		++numDoubles;
		doubleValue += strtod(yytext,NULL); }

{operator} { 	printf("operator (%c)\n",yytext[0]);
		++numOperators; }

{op_bracket} { 	printf("nawias otwierajacy\n");
		++numBrackets; }

{cl_bracket} { 	printf("nawias zamykajacy\n");
		++numBrackets; }

.|\n { /* pomijaj niedopasowane znaki */ }

%%

int main() {
	printf("Poczatek skanowania...\n");
	yylex();
	printf("\nKoniec skanowania\n");
	printf("\tPrzeczytano %d liczb całkowitych o łacznej wartosci %d\n",
	numInts,intValue);
	printf("\tPrzeczytano %d liczb rzeczywistych o łacznej wartosci %f\n",
	numDoubles,doubleValue);
	printf("\tUzyto %d nawiasow oraz %d operatorow\n\n",numBrackets,numOperators);

	return 0;
}

Ja, jako żółtodziób nie widzę związku tych 2 kodów, a treścią polecenia , chyba że jestem w błędzie i wykładowca faktycznie miał rację

0

Pomożecie jakoś wybrąć z tego ? no ten program nie powinien być zbyt długi, uważam że do 100 linii to jest max dla niego

1

To raczej ma wyglądać mniej więcej tak:

%{
#include <stdio.h> 
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <locale.h>

struct tm parseDateA(const char* s)
{
    .....
}

struct tm parseDateB(const char* s)
{
    .....
}

void printNormalDate(struct tm t)
{
    char buf[20];
    strftime(buf, sizeof buf, "%Od-%B-%y", &t);
    printf("%s", buf);
}
%}

dateA  ....
dateB  ....
dateC  ....

%%

{dateA}		printNormalDate(parseDateA(yytext));
{dateB}		printNormalDate(parseDateB(yytext));
{dateC}		printNormalDate(parseDateC(yytext));
.|\n		printf("%s", yytext);

%%

int main() {
    setlocale(LC_ALL, "");
	yylex();
	return 0;
}
0

Nigdy nie używałem tego narzędzia, wiec spróbowałem i wygenerowało mi coś takiego: https://godbolt.org/z/7K18n7xzx
godbolt nie obsługuje polskiego locale, ale na docelowej maszynie zadziała.

2

Jestem przeciwnikiem dawania gotowców, ale coś nabazgrałem, więc daje z parodniowym opóźnieniem i niekompletne.

Dosłowne Copy-Paste z mojego terminala (domyślnie mam ustawiony angielski):

4progFlex $ ls
DateFixer.c.flex	in.txt
4progFlex $ cat in.txt 
Dzis jest 20.04.2020 jutro bedzie 21-4-2020, ciekawe za ile dni skonczy sie kwarantanna moze 12/05/2020 a co sie stanie jak potrwa do 01-czerwiec-2020 oby nie bo chcialbym zaplanowac wakacje od 1-7-2020.

4progFlex $ cat DateFixer.c.flex 
%{
#include <stdio.h> 
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <locale.h>

void printNormalDate(struct tm t)
{
    char buf[32];
    strftime(buf, sizeof buf, "%Od-%B-%y", &t);
    printf("%s", buf);
}

struct tm parseDateFromat(const char* date, const char* format)
{
    struct tm r = {};
    
    sscanf(date, format, &r.tm_mday, &r.tm_mon, &r.tm_year);
    r.tm_year -= 1900;
    r.tm_mon -= 1; 
    
    return r;
}

void printConvertDate(const char* date, const char* inFormat)
{
    printNormalDate(parseDateFromat(date, inFormat));
}
%}

dateDash	[0-3]?[0-9]-[0-1]?[0-9]-[1-9][0-9]{3}
dateSlash	[0-3]?[0-9]\/[0-1]?[0-9]\/[1-9][0-9]{3}
dateDot		[0-3]?[0-9]\.[0-1]?[0-9]\.[1-9][0-9]{3}

%%

{dateDash}    printConvertDate(yytext, "%d-%d-%d");
{dateSlash}   printConvertDate(yytext, "%d/%d/%d");
{dateDot}     printConvertDate(yytext, "%d.%d.%d");
.|\n          printf("%s", yytext);

%%

int main() {
    setlocale(LC_ALL, "");
    yylex();
    return 0;
}

4progFlex $ flex DateFixer.c.flex 
4progFlex $ ls
DateFixer.c.flex	in.txt			lex.yy.c
4progFlex $ gcc lex.yy.c -O2 -o DateFixer -lfl
4progFlex $ ./DateFixer <in.txt
Dzis jest 20-April-20 jutro bedzie 21-April-20, ciekawe za ile dni skonczy sie kwarantanna moze 12-May-20 a co sie stanie jak potrwa do 01-czerwiec-2020 oby nie bo chcialbym zaplanowac wakacje od 01-July-20.

4progFlex $ export LANG=pl_PL.utf-8
4progFlex $ ./DateFixer <in.txt 
Dzis jest 20-kwietnia-20 jutro bedzie 21-kwietnia-20, ciekawe za ile dni skonczy sie kwarantanna moze 12-maja-20 a co sie stanie jak potrwa do 01-czerwiec-2020 oby nie bo chcialbym zaplanowac wakacje od 01-lipca-20.

4progFlex $ 

1 użytkowników online, w tym zalogowanych: 0, gości: 1