Własny język programowania. Część 2: Parser + wyrażenia = kalkulator

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

Konstruktor

Ponieważ ustawiamy wskaźnik za ostatnim znakiem danego "poziomu", warto, by wskaźnik zawsze na coś pokazywał. Dlatego dodamy na sam koniec analizowanego tekstu tzw. strażnika, który będzie znakiem (a więc zawsze będzie można odczytać kolejny znak), ale nie będzie rozpoznawany jako żaden operator, liczba ani nazwa zmiennej. Strażnik nazywa się EOS (ang. end of string). Konstruktor parsera bierze jako argument tekst do analizy, dodaje na jego końcu strażnika i ustawia wskaźnik na sam początek tekstu:

1
2
3
4
5
6
const char EOS = NULL;
 
Parser::Parser(string input) : input(input), position(0)
{
  input.push_back(EOS);
}

Pomijanie białych znaków

Ponieważ wyrażenie może zawierać białe znaki, warto mieć metodę, która przesunie wskaźnik na pierwszy element za ciągiem białych znaków, tak jak pokazuje poniższy obrazek (kolor zielony na obrazkach pokazuje "obszar zainteresowań" danej metody):

Implementacja samej metody jest bardzo prosta:

1
2
3
4
5
void Parser::skip_whitespace()
{
  while (isspace(input[position]))
    position++;
}

Oglądanie znaku pokazywanego przez wskaźnik

Często będziemy chcieli obejrzeć znak, który pokazywany jest przez wskaźnik. Będziemy to robić, żeby zobaczyć jaki jest następny interesujący znak, a że białe znaki nie są zbyt interesujące, warto połączyć podglądanie znaku z pomijaniem ich:

1
2
3
4
5
char Parser::look_ahead()
{
  skip_whitespace();
  return input[position];
}

Parsowanie wyrażeń

Ponieważ wyrażenie jest "sumą", by sparsować wyrażenie, wystarczy sparsować sumę, a następnie sprawdzić czy kolejnym znakiem (oczywiście z pominięciem białych znaków) jest koniec tekstu. Pamiętajmy, że po sparsowaniu "sumy", wskaźnik pokazuje na pierwszy znak za "sumą":

1
2
3
4
5
6
7
8
Expression* Parser::parse_Expression()
{
  Expression* e = parse_sum();
  if (look_ahead() == EOS)
    return e;
  else
    throw Not_parsed();
}

Parsowanie "sum"

Metoda parsowania "sum" interesuje się kolejnymi składnikami oddzielonymi operatorami '+' i '-':

Kod metody parsowania "sum" jest prosty. Najpierw parsujemy pierwszy składnik (każda "suma" ma przynajmniej jeden), a potem patrzymy na znak za składnikiem. Jeśli jest to '+' lub '-', to znaczy, że w "sumie" jest kolejny składnik. Jeśli nie, to kończymy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Expression* Parser::parse_sum()
{
  Expression* e = parse_mult();
  char c = look_ahead();
 
  while(c == '+' || c == '-')
  {
    position++;
    e = new Binary_operator(c, e, parse_mult());
    c = look_ahead();
  }
 
  return e;
}

Wiersz position++; przesuwa wskaźnik znad znaku '+' lub '-' nad pierwszy znak kolejnego składnika.

Parsowanie składników

Składnik to czynniki połączone znakami '*', '/' i '%':

Parsowanie czynników jest bardzo podobne do parsowania "sum":

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Expression* Parser::parse_mult()
{
  Expression* e = parse_term();
  char c = look_ahead();
 
  while(c == '*' || c == '/' || c == '%')
  {
    position++;
    e = new Binary_operator(c, e, parse_term());
    c = look_ahead();
  }
 
  return e;
}

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

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com