Własny język programowania. Część 4: Parser programów

15.07.2010 - Maciej Piróg
TrudnośćTrudność

Parser

Parser dla całego języka programowania powstanie z rozszerzenia parsera dla wyrażeń arytmetycznych, który powstał w 2. części cyklu. Po prostu dodamy do niego metody parsujące wszystkie rodzaje wyrażeń:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Parser
{
    string input;
    size_t position;
 
  public:
    Parser(string input);
 
    void skip_whitespace();
    char look_ahead();
 
    Expression* parse_sum();
    Expression* parse_mult();
    Expression* parse_term();
    Expression* parse_Constant();
    Expression* parse_Variable();
    Expression* parse_paren();
 
    string parse_identifier();
 
    Program* parse_Program();
    Program* parse_block();
    Program* parse_instruction();
    Program* parse_Read();
    Program* parse_Write();
    Program* parse_If();
    Program* parse_While();
    Program* parse_Assign(string v);
};

Jak widać, nasz parser ma już bardzo dużo metod, każda z nich jednak wykonuje bardzo prostą czynność.

Dociekliwy czytelnik zauważy, że metoda parse_Assign bierze dodatkowy argument. Dlaczego? Spójrzmy na główną metodę parsowania instrukcji. Korzysta ona z obserwacji, że każda instrukcja zaczyna się od słowa kluczowego (if, while, read, write, skip), nazwy zmiennej lub nawiasu '{'. Metoda czyta więc identyfikator lub słowo kluczowe, używając do tego metody parse_identifier, która działa dokładnie tak samo, jak poznana w 2. części cyklu metoda parse_Variable, tylko zwraca typ string. Na podstawie tego identyfikatora, dokonuje decyzji, z którą instrukcją mamy do czynienia, i wywołuje odpowiednią metodę parsującą:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Program* Parser::parse_instruction()
{
  char c = look_ahead();
  if (c == '{')
  {
    position++;
    Program* p = parse_block();
    if (look_ahead() == '}')
    {
      position++;
      return p;
    }
    else
      throw Not_parsed("'}' expected");
  }
  else if (isalpha(c))
  {
    string s = parse_identifier();
    
    if (s == "read")
      return parse_Read();
    else if (s == "write")
      return parse_Write();
    else if (s == "if")
      return parse_If();
    else if (s == "while")
      return parse_While();
    else if (s == "skip")
      return new Skip();
    else
      return parse_Assign(s);
  }
  else
    throw Not_parsed("identifier or a keyword expected");
}

Po sparsowaniu identyfikatora, wskaźnik na kolejny znak ustawiony jest za identyfikatorem (lub słowem kluczowym)! Dlatego, jeśli przeczytamy np. słowo if, to wywołujemy metodę parsującą instrukcję warunkową, która już nie próbuje czytać słowa if, które zostało przeczytane przez metodę parse_instruction:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Program* Parser::parse_If()
{
    Expression* e = parse_sum();
    Program* p = parse_instruction();
    if (isalpha(look_ahead()))
    {
      if(parse_identifier() == "else")
      {
        Program* q = parse_instruction();
        return new If(e, p, q);
      }
      else
        throw Not_parsed("'else' expected");
    }
    else
      throw Not_parsed("'else' expected");
}

Jeśli instrukcją jest przypisanie postaci x = expr, to metoda parse_instruction 'zjada' nazwę zmiennej, tak samo jak słowo kluczowe if w powyższym przypadku. Dlatego przekazuje przeczytaną nazwę do metody, która parsuje przypisania:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Program* Parser::parse_instruction()
{
  // ...
    string s = parse_identifier();
    // ...
      return parse_Assign(s);
  //...
}
 
Program* Parser::parse_Assign(string v)
{
  char c = look_ahead();
  if (c == '=')
  {
    position++;
    Expression* e = parse_sum();
    return new Assign(v, e);
  }
  else
    throw Not_parsed("'=' expected");
}

Pozostałe instrukcje parsujące są analogiczne, bardzo gorąco zachęcamy do przejrzenia pełnego kodu.

5
Twoja ocena: Brak Ocena: 5 (1 ocena)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com