Autor Wątek: Parser i błędy.  (Przeczytany 2079 razy)

Antrykot

  • Gość
# Luty 05, 2006, 22:41:25
Witam.

Pisze parser dla prostego skryptu który ma opisywać zasoby, głównie okna dialogowe i kontrolki.
I mam problem z sygnalizacją błędu. Mianowicie są różne funckje typu prs_int, prs_text, czy prs_keyword.
I teraz jak zasygnalizować błąd. Bo załóżmy że pierwsze jedzie prs_int. "Widzi" jakieś cyfry jedzie dalej, ale spotyka litere i daje se spokój. Nie może parsować dalej, ale nie może też zasygnalizować błędu, bo poźniej przejedzie np prs_keyword i zaklasyfikuje dany ciąg jako słowo kluczowe.
Najprostszym wyjściem jest na końcu pętli główne parsera po prostu wywalić errora z numerem lini, ew pozycją w pliku, ale wtedy można wyświetlić co najwyżej syntax error, a ja bym wolał coś bardziej dokładnego.

Może podda ktoś mi jakiś pomysł ? :)

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Antrykot

  • Gość
# Luty 05, 2006, 23:24:42
Ja to robie tak, przy parsowaniu wszystko traktuje jako stringi a dopiero potem te stringi
parsuje na liczbe. Gdy zamiana z string'a do powiedzmy int'a się nie powiedzie to pobieram
aktualną pozycje w pliku i zwracam błąd.

pozdro
spax.

Antrykot

  • Gość
# Luty 06, 2006, 00:06:19
Jak na razie wymyśliłem tylko, żeby na końcu pętli dodać funkcje, która sprawdza cały string pod kątem występowania liter, cyfr, 'znaczków', nawiasów itp
I teraz w zależności od tego ile z nich sie pojawiło w danym stringu, taki będzię komunikat.

Powiedzmy że dla każdego keyworda na początku musi sie pojawić '#'. Jeżeli string zawiera # i litery, ale prs_keyword go nie zidentyfikował, to mamy 'undeclared identyfier' lub coś w tym stylu.
I tak dalej.

Spax : Ale to że coś ma cyfre, i nie da sie tego przeparsować na INTA, to nie znaczy że nim jest lub miało być. Może to być np kawałek textu w w otwartym cudzysłowiu np "costam768
Ani prsl_Text ani prs_Int tego nie łyknie, ale to prs_Text miał wywalić errora.

Offline Złośliwiec

  • Użytkownik
    • Dark Cult

# Luty 06, 2006, 09:21:43
Ja robię tak, że wszelkie miejsca w skrypcie, w których występują dane mieszane (liczby i stringi, albo same liczby) są rozwalane przez osobną funkcję:

BOOL cPARSER_FILE::nav_param(LPCSTR ptype, ...)
{
 va_list lista;
 DWORD pcount=0;
 LPVOID wsk;
 union
 {
  string *s;
  DWORD  *d;
  WORD   *w;
  BYTE   *b;
  float  *f;
 } cwsk;
 string cval_s;
 union
 {
  DWORD  d;
  WORD   w;
  BYTE   b;
  float  f;
 } cval;

 va_start(lista, ptype);

 while( pcount<lstrlen(ptype) )
 {
  //pobierz dane z bufora
  if(!nav_next()) return FALSE; 
  //pobierz kolejny parametr
  wsk = va_arg(lista,LPVOID); //wczytaj adres parametru
  //rzutowanie adresu oraz konwersja i zapisanie wartości
  switch(ptype[pcount])
  {
   case 's':
   {
    cwsk.s = static_cast<string*>(wsk); 
    cval_s = expr;
    *cwsk.s = cval_s;
   }
   break;
   case 'd':
   {
    cwsk.d = static_cast<DWORD*>(wsk);
    cval.d = static_cast<DWORD>(_atoi64(expr.c_str()));
    *cwsk.d = cval.d;
   }
   break;
   case 'w':
   {
    cwsk.w = static_cast<WORD*>(wsk);
    cval.w = static_cast<WORD>(atoi(expr.c_str()));
    *cwsk.w = cval.w;
   }
   break;
   case 'b':
   {
    cwsk.b = static_cast<BYTE*>(wsk);
    cval.b = static_cast<BYTE>(atoi(expr.c_str()));
    *cwsk.b = cval.b;
   }
   break;
   case 'f':
   {
    cwsk.f = static_cast<float*>(wsk);
    cval.f = static_cast<float>(atof(expr.c_str()));
    *cwsk.f = cval.f;
   }
   break;
   default:
   {
    Log.append("\r\nUnrecognized character - " + ptype[pcount]);
    return FALSE;
   }
  }
  ++pcount;
 }

 va_end(lista);
 return TRUE;
}

Jak widać, nie ma tutaj żadnego sprawdzania, czy dany ciąg jest liczbą czy nie - funkcje typu atoi, atof zwracają 0, jeśli nie można przekonwertować tekstu na liczbę. Wystarczy, że dodasz do tego sprawdzanie, czy ciąg jest rzeczywiście równy "0" i już masz to, co chciałeś osiągnąć.

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

# Luty 06, 2006, 12:30:21
Ja w swoich parserach określam to tak, że funkcja mająca za zadanie sparsować coś konkretnego próbuje to zrobić. Jeśli się uda, przesuwa indeks parsowanego łańcucha dalej, zwraca przez parametry wskaźnikowe odczytane informacje (albo je gdzieś zachowuje) i zwraca true. Jeśli się jej nie uda, pozostawia indeks nienaruszony i zwraca false.

Jeśli natomiast parsowany element jest na pewno tym a nie innym elementem tylko występuje w nim ewidentny błąd składniowy, to musisz jakoś zorganizować sobie obsługę błędów. Albo poprzez zwracanie przez funkcje parsujące jakiegoś specjalnego kodu błędu, albo poprzez rzucanie wyjątków.

Offline yorp

  • Użytkownik
    • ProfessionGG Project

# Luty 06, 2006, 12:45:29
Ja w swoim jezyku skryptowym, mam zalozenie, ze wszystkie zmienne sa zapisywane jako tekst, z tym ze przy parsowaniu, jesli wartosc zmiennej zaczyna sie od " (cudzysłow), to traktuje dany ciag jako slowa, w innym przypadku jako liczbe, a gdy wartosci wogole nie podamy - jako ciag nieokreslony (do niego moge ladowac klasy itp).

Antrykot

  • Gość
# Luty 07, 2006, 12:10:03
Parser sie , pisze, 'moja' koncepcja jest chyba taka sama jak Regedita, bo pochodzi z jego artykułu :D
Co do tych błędów, to narazie spróbuje tak jak mówiłem, na końcu pętli zależnie od tego co zawiera dany string, wywołać odp errora. Jeśli to nie zda egzaminu, to spróbuje sprawdzać w każdej funkcji.
THX z opdowiedzi :)