[ bozilla @ 08.04.2009. 19:49 ] @
Leksicki analizator za podskup SQL jezika. Radim u GNU flex-u i cini mi se da poslu nema kraja, ustvari muci me da sam sve napravila pogresno, radim previse pjesacki. Npr. kako izaci na kraj sa ovim:

Code:
CREATE TABLE [ IF NOT EXISTS ] table_name
  ( column_declare1, column_declare2, constraint_declare1, ... )
  

column_declare ::= column_name type [ DEFAULT expression ]
  [ NULL | NOT NULL ] [ INDEX_BLIST | INDEX_NONE ] 

type ::= BIT | REAL | CHAR | TEXT | DATE | TIME |
  FLOAT | BIGINT | DOUBLE | STRING | BINARY | NUMERIC |
  DECIMAL | BOOLEAN | TINYINT | INTEGER | VARCHAR |
  SMALLINT | VARBINARY | TIMESTAMP | LONGVARCHAR |
  JAVA_OBJECT | LONGVARBINARY 

constraint_declare :: = [ CONSTRAINT constraint_name ]
  PRIMARY KEY ( col1, col2, ... ) |
  FOREIGN KEY ( col1, col2, ... ) REFERENCES f_table [ ( col1, col2, ... ) ]
             [ ON UPDATE triggered_action ] [ ON DELETE triggered_action ] |
  UNIQUE ( col1, col2, ... ) |
  CHECK ( expression )
  [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
  [ NOT DEFERRABLE | DEFERRABLE ]

triggered_action :: =
  NO ACTION | SET NULL | SET DEFAULT | CASCADE


Previse je opcionih elemenata, previse toga sto treba definisati.
A sad zamislite ostatak SQL sintakse koju treba obraditi, jer ovo je samo jedan izraz!
Ima li neko iskustva sa ovim i moze li mi pomoci ili me uputiti?
Hvala.

[Ovu poruku je menjao bozilla dana 09.04.2009. u 14:55 GMT+1]
[ Nedeljko @ 09.04.2009. 08:08 ] @
Ako budeš hteo da pokriješ ugnježdene upite, teško ćeš samo sa FLEX-om da izažeš na kraj. Problem je u tome što taj jezik nije regularan, pa se ne može opisati flex-om. Ako nećeš ugnježdene upite, onda bi trebalo da je posao dovršiv u flex-u. Treba ti parser, koji obično koristi neki leksički analizator. FLEX je generator leksičkih analizatora, a ne parsera. Za parser koristi neki od generatora parsera. Odgovarajuća GNU kombinacija je FLEX / Bison. Leksički analizator treba samo da izdvaja tokene (zagrade, ključne reči itd.). Naravno, ključne reči treba da definišeš u FLEX-u u odgovarajućoj definiciji. Od toga nema be\anja.

Opcioni parametri nisu problem čak ni za regularne jezike. Ako je A neki patern, onda možeš definisati Aopt patern kome odgovara prazna reč ili reč koja odgovara paternu A. Onda tamo gde se A pojavljuje opciono treba u definiciji koristiti Aopt. Naravno, u FLEX-u imaš regularne izraze gde možeš zadati broj ponavljanja nekog paterna u nekoj definiciji (recimo, na <=1 ako je opcioni).

Međutim, to je pogrešan pristup. Leksički analizator treba da izdvaja samo tokene.
[ bozilla @ 09.04.2009. 14:20 ] @
Za sintaksnui analizu koristim Yacc, medjutim, u ovom slucaju, treba odraditi samo leksicku provjeru.

Malo si mi rasvijetlio moj problem. Ja MORAM ici pjesice jer ovaj jezik ne mogu opisati regularnim izrazom, vec polako jedno po jedno. Zato ima dosta tog sljakanja na prazno.
Ono sto me muci kod opcionih elemenata nije kako cu ja njih definisati, (stavljam ? za nula ili jedno pojavljivanje) vec sto idem dalje nekako mi izrazi "divergiraju", nikako s njima da dodjem do kraja, uvijek se pojavi jos neki uslov ili opcija.
Napravicu nesto pametno pa cu demonstrirati gdje zapinjem.
Veliko hvala na pomoci ;)
pomogao si mi da bolje sagledam svoj problem. ljudi se veoma slabo bave ovim, tesko je naci nekoga da uopste razumije o cemu se radi. Ako imas jos kakvih sugestija, rado cu ih prihvatiti.
pozz
[ Nedeljko @ 10.04.2009. 07:57 ] @
Citat:
bozilla: Za sintaksnui analizu koristim Yacc, medjutim, u ovom slucaju, treba odraditi samo leksicku provjeru.


Kakvu sad proveru? Misliš li na proveru da li je upit sintaksno ispravan?

FLEX se koristi sam za izdvajanje tokena. U tvom slučaju su tokeni ključne reči, zagrade, operatori, stringovi, numeričke konstante, identifikatori (imena kolona, tabela itd.) i još ponešto, a ne celi upiti. Ako želiš da proveriš sintaksnu ispravnost celog upita, to bi trebao da rešiš u YACC-u (akonjega koristiš), a ne FLEX-u. FLEX treba samo da ima leksički analizator da se ne bi YACC zamajavao sa npr. ključnim rečima, već da bi dobio jedan kod za recimo CREATE.
[ Aleksandar Ružičić @ 10.04.2009. 19:38 ] @
ja sam davno radio nesto slicno (pravio sam neki svoj subset sql-a), ali nisam radio u yacc-u, vec u gold parser builderu (zapravo samo sam ga korisito da generisem dfa i lalr tabele, parser i tokenizer sam pisao rucno).

na sajtu gold parsera imas gotove gramatike za nekoliko jezika, medju kojima i ANSI SQL: http://www.devincook.com/goldparser/grammars/index.htm#Languages
mozes da vidis kako je ta BNF gramatika napisana pa iskoristi ideje...
[ bozilla @ 12.04.2009. 19:26 ] @
napravila sam nesto. prikazacu dio koda: (ne znam zasto se ovdje razletio)

Code:

%option noyywrap
SLOVO                                      [A-Za-z]
CIFRA                                   [0-9]
DATE                                           {CIFRA}{CIFRA}{CIFRA}{CIFRA}"-"[0-12]"-"[0-31]     
TIME                                           {CIFRA}{CIFRA}":"{CIFRA}{CIFRA}":"{CIFRA}{CIFRA}
REAL                                           [+\-]?{CIFRA}+\.{CIFRA}+(e[+\-]?{CIFRA}+)?
INTEGER                                   [+\-]?{CIFRA}+
STRINGK                                   [^'|^"]
STRING                                   '{STRINGK}+'

IDENT                                   {SLOVO}({SLOVO}|{CIFRA})*

%% 
CREATE|create                    printf("prepoznat CREATE");
SELECT|select                           printf("\nprepoznat SELECT");
AND|and                           printf("\nprepoznato AND");
IS|is                           printf("\nprepoznat IS");

                            .
                            .
{DATE}                    printf("\nprepoznat datum");
{REAL}                    printf("\nrealni broj%s",yytext);
REAL|FLOAT|DECIMAL|DOUBLE        printf("tip realnog broja");
{INTEGER}                        printf("\ncijeli broj %s",yytext);
INTEGER|INT|BIGINT|SMALLINT|TINYINT|MEDIUMINT                     printf("prepoznat cjelobrojni tip");
{STRING}                        printf("\nstring %s",yytext);
CHAR|TEXT|VARCHAR|LONGVARCHAR|BINARY|VARBINARY|LONGVARBINARY      printf("prepoznat stringovni tip");            
{IDENT}                    printf("\nprepoznat identifikator %s",yytext);
"."                                        printf("\nprepoznata tacka");
","                                       printf("\nprepoznat zarez");
":"                            printf("\nprepoznata dvotacka");
"="                             printf("\nprepoznat jednako");
"!="|"<>"                               printf("\nprepoznato razlicito");
"*"                            printf("\nprepoznat operator mnozenja");

                                    .
                                    .
%%
main()
{yylex();
}



ovo za sad radi ono sto bi trebalo da radi. uglavnom.dovoljno za prolaz zanima me vase misljenje.
ono sto znam da ne radi to je datum i vrijeme. trebalo bi ih napisati kao cifre formata YY-MM-DD i HH:MM:SS, ali meni to ne ide.
takodje, imam problem sa stringovima. ne umijem ih izdvojiti ako su u upotrebi i pod jednostrukim i pod dvostrukim navodnicima, vec samo jednim od njih.ja sam napravila da ih prepoznaje ako su pod jednostrukim. eto. ako znate sta o tome..
[ 1jedini @ 13.04.2009. 09:55 ] @
Gde ti je underscore?
[ bozilla @ 14.04.2009. 09:41 ] @
mislis u imenu tabele?
u pravu si. identifikator bi trebao biti visi nego skup slova i brojeva.
neki prijedlog za datum i vrijeme?
[ djoka_l @ 14.04.2009. 11:30 ] @
A zašto ti je potrebno da izdvajaš posebno datum i vreme. Možda u nekim dijalektima SQLa postoji tako nešto, ali u Oracle bazi datum i vreme je uvek string literal, na primer:

Code:
SELECT * from MyTable
WHERE MyDate = to_date('14/04/09 23:15', 'DD/MM/RR HH24:MI')


Ovde je datum jednostavno string literal i nikakva dodatna leksička ili sintaksna analiza nije potreba. Ovaj literal se tek u run-timeu interpretira.

Uzgred, zakačio sam ti jedan Flex fajl, koji sam davno pravio iz zezanja za parsiranje PL/SQL (a bogami i SQL) skriptova, ali nikada nisam našao vremena da završim. Možda će ti koristiti.

[Ovu poruku je menjao djoka_l dana 14.04.2009. u 12:42 GMT+1]
[ djoka_l @ 14.04.2009. 12:03 ] @
Uzgred, pronašao sam i ova dva fajla u kojem je lista rezervisanih reči u SQL-u i u PL/SQL-u. Ne garantujem da je lista kompletna, a ne znam ni tačno na koje se verzije odnosi...

Dve zamerke na tvoj lex fajl:

1. Nemoj da prepoznaješ znak + i - kao deo numeričkog literala. Ovi znaci mogu biti unarni ili binarni operatori. Na primer, kako bi tvoj analizator prepoznao izraz 1+1?
2. Pozivaj flex sa opcijom "-i" kako bi dobila case-insensitive parser. Tvoj parser ne bi prepoznao komande SeLeCt i druge kombinacije malih/velikih slova, a SQL je sace-insensitive i svi ti oblici su dozvoljeni.

[Ovu poruku je menjao djoka_l dana 14.04.2009. u 13:28 GMT+1]
[ bozilla @ 15.04.2009. 16:08 ] @
@1jedini, hvala sto si mi skrenuo paznju, bilo bi jako lose da je ostalo onako.

@djoka_l, hvala.
ove sugestije su bile i vise nego korisne!
strasno su mi pomogle, kao i dodaci postovima. bas mi je drago da ste svoje znanje podijelili sa mnom. valjda ce jos nekome pomoci. ako se jos necega sjetite..;)