Drzewa, Szablony i reszta menażerii

Analizator leksykalny i składniowy

Na początek znana już gramatyka. Pozbawiona jest ona jednak wszystkich akcji pracowicie poprzednio wstawianych. Teraz te akcje będą w innych plikach. Tu chcemy tylko wygenerować drzewo (Abstrakcyjne Drzewo Składniowe - Abstract Syntax Tree).

grammar Expr;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

output=AST oznacza, że chcemy produkować abstrakcyjne drzewo składniowe. ASTLabelType=CommonTree określa klasę, do której będą należeć węzły tworzonych drzew. Nic nie stoi na przeszkodzie aby utworzyć swoją klasę ale powinna ona dziedziczyć po CommonTree.

@header {
// package com.sample;
}

Jeśli projekt umieścimy w pakiecie (java nas będzie lubić za to!) to powinniśmy to tutaj podać. Poniżej to samo dla analizatora leksykalnego.

@lexer::header {
//  package com.sample;
}

prog
    : (stat )+ EOF!;

stat
    : expr NL -> expr

Jeden sposób określania jak należy skonstruować fragment drzewa: "wezmisz to, co expr przyniesie i za pyzatego miesiączka wrazisz w drzewo".

    
    | ID PODST expr NL -> ^(PODST ID expr)

Wersja bardziej zaawansowana: "i wystrugasz PODST , a nazwiesz go korzeniem, a podepni do niego ID , a też to, co za expr em przywlecze się, a je od tej pory dziećmi nazywać bedziesz".

    | NL ->
    ;

A tu wersja najprostsza: "zostaw te drzewa w spokoju, połóż się, odpocznij". W każdej wersji powyżej NL do drzewa nie trafia, bo nikomu tam nie jest potrzebny.

expr
    : multExpr
      ( PLUS^ multExpr
      | MINUS^ multExpr
      )*
    ;

Tu mamy drugi sposób sterowania tworzeniem fragmentu drzewa. W momencie napotkania w strumieniu wejściowym elementu oznaczonego tu ^ , robimy z niego korzeń, a to co dotychczas mieliśmy zrobione podpinamy doń jako dziecko.

multExpr
    : atom
      ( MUL^ atom
      | DIV^ atom
      )*
    ;

atom
    : INT
    | ID
    | LP! expr RP!
    ;

Kolejny element drugiego sposobu sterowania tworzeniem fragmentu drzewa. Element opatrzony ! należy zignorować przy tworzeniu drzewa.
Ważne! W jednej regule nie mieszamy sposobów, czyli albo reguły przepisywania (->), albo znaczki ^ !.

Niżej mamy znane już reguły leksykalne.
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;

INT : '0'..'9'+;

NL : '\r'? '\n' ;

WS : (' ' | '\t')+ {$channel = HIDDEN;} ;


LP
	:	'('
	;

RP
	:	')'
	;

PODST
	:	'='
	;

PLUS
	:	'+'
	;

MINUS
	:	'-'
	;

MUL
	:	'*'
	;

DIV
	:	'/'
	;

Analizator drzew

Tutaj mamy wybór.

  1. Jeśli chcemy wykonywać obliczenia i drukować wynik tak, jak na poprzednich zajęciach, idziemy tu. (Drugie zajęcia.)
  2. Jeżeli chcemy tworzyć kolejne, przetworzone drzewo, idziemy tu. (Nie korzystamy z tego na zajęciach.)
  3. Jak chcemy korzystać z szablonów, idziemy tu. (Trzecie zajęcia.)