PLY (Python Lex-Yacc)

Maciej Nowak & Arkadiusz Wieczorek

Plan prezentacji

  1. Problematyka
  2. Wstęp do gramatyki
  3. PLY, czyli YACC & LEX w użyciu
  4. Działanie przykładowej aplikacji
  5. Podsumowanie

Problem

Komunikacja człowiek - komputer

Przykłady

urządzenia wskazujące

polecenia w terminalu

panele dotykowe

komendy głosowe

kontrolery ruchu

komunikacja obrazowa

Przetwarzanie języka naturalnego

Gramatyka

Definicja gramatyki

Jest to metoda opisująca dopuszczalne sekwencje wyrazów należących do leksykonu

Gramatyka

Leksykon

{trzy, troje, siedem, jedna, chłopców, drużyny, piłek, piłka, małych, duże, wielka, niebieska, owalna}

  • trzy duże drużyny
  • troje małych chłopców
  • siedem małych piłek
  • jedna wielka niebieska owalna piłka

 

  • trzy
  • troje chłopców małych
  • siedem małych dużych piłek
  • jedna wielka piłek

Sekwencje dopuszczalne

Sekwencje niedopuszczalne

Gramatyka formalnie

Gramatyka jest zbiorem zasad dla ciągów tekstowych w języku formalnym. Zasady opisują w jaki sposób tworzyć ciągi tekstowe z alfabetu języka w taki sposób, aby były one zgodne ze składnią języka. Gramatyka nie opisuje znaczenia ciągu tekstowego lecz tylko jego formę.

G = <N, V, P, S>

N - zbiór symboli nieterminalnych (symbole pomocnicze)
V  - zbiór symboli terminalnych (słowa leksykonu)
P - zbiór produkcji języka (zasady gramatyki)
S - symbol startowy (jeden z symboli nieterminalnych)

Gramatyka

Zapis formalny

Przykład

G = <N, V, P, S>

Zbiór symboli nieterminalnych

N = {cmd, art, color, size, number, shape, kind}

Zbiór symboli terminalnych

V  = {trzy, troje, siedem, chłopców, drużyny, piłek, piłka, małych, duże, wielka, niebieska, owalna} 

Zbiór produkcji języka

S = cmd

P = 

cmd - number art
  art - size color shape kind
  number - "trzy"
  number - "troje"
  number - "jedna"
  number - "siedem"
  size - "małych"
  size - "duże"
  size - "wielka"
  color - "niebieska"
  shape - "owalna"
  kind - "chłopców"
  kind - "drużyny"
  kind - "piłek"
  kind - "piłka"

Symbol startowy

Gramatyka

Analiza leksykalna

polega na podzieleniu tekstu na tokeny, a następnie przypisanie każdemu z nich typu z leksykonu. Program, który dokonuje tej analizy nazywany jest lexer (np.: LEX).

IN:       trzy duże drużyny

OUT:   trzy: NUMBER
            duże: SIZE
            drużyny: KIND

IN:       troje małych chłopców

OUT:   troje: NUMBER
            małych: SIZE
            chłopców: KIND

IN:       siedem małych piłek

OUT:   siedem: NUMBER
            małych: SIZE
            piłek: KIND

IN:       jedna wielka niebieska owalna piłka

OUT:   jedna: NUMBER
            wielka: SIZE
            niebieska: COLOR
            owalna: SHAPE
            piłka: KIND

Definicja

Analiza składniowa

sprawdza czy wejście spełnia zasady gramatyki. W przypadku poprawności, może zwrócić ciąg podejmowanych akcji. Program, który wykonuje tą analizę zwany jest parser (np.: YACC)

IN:       jedna:NUMBER wielka:SIZE niebieska:COLOR owalna:SHAPE piłka:KIND

OUT:   Success
            Action: Save into local database
            Action: Send data to server

IN:       jedna:SIZE owalna:SHAPE niebieska:COLOR wielka:SIZE piłka:KIND

OUT:   Failure

Definicja

PLY

Czym jest PLY?

LEX

YACC

ANALIZA LEKSYKALNA

ANALIZA
SKŁADNIOWA
 

Przykładowa aplikacja

Klub piłkarski zamawia z hurtowni stroje sportowe do szatni klubowej. Zamówienie dotyczy podkoszulek, koszulek meczowych oraz spodenek w różnych rozmiarach, a także w dwóch wariantach kolorystycznych: niebieskim i czerwonym. Program ma za zadanie zebrać pełne zamówienie jako zestawienie różnych wariantów.

 

Na przykładzie tej aplikacji zostanie przedstawiony schemat budowania programu w PLY.

Budowanie kompilatora z użyciem PLY

  • Definicja zbioru tokenów

  • Wyznaczenie zbioru wyrazów (leksykon)

  • Uruchomienie lex
     

  • Ustalenie kolejności zasad

  • Definicja zasad parsowania

  • Uruchomienie yacc
     

  • Start parsera

Definicja zbioru tokenów

tokens = (
	'NUMBER', 'SIZE', 'COLOR', 'KIND', 'ACTION'
	)

Wyznaczenie zbioru wyrazów (leksykon)

t_ACTION = r'db|list'

def t_NUMBER(t):
	r'[\+]{0,1}[0-9]+[\.][0-9]+|[\+]{0,1}[0-9]+'
	print(t.type, t.value)
	return t

def t_SIZE(t):
	r'[SML]|XL'
	print(t.type, t.value)
	return t

def t_COLOR(t):
	r'blue|red'
	print(t.type, t.value)
	return t

def t_KIND(t):
	r'jerse(y|ys)|shorts|shir(t|ts)'
	print(t.type, t.value, '\n')
	return t

# Ignored characters
t_ignore = " \t"

def t_newline(t):
    r'\n+'
    t.lexer.lineno += t.value.count("\n")

def t_error(t):
    t.lexer.skip(1)

Uruchomienie lex

import ply.lex as lex

# Tokens
# ...

# Definitions for tokens
# ...


# Build the lexer
lexer = lex.lex()

Ustalenie kolejności zasad

def p_expression(p):
    '''expression : actionRule
		  | mainRule'''

# Definitions of rules
# ...

Definicja zasad parsowania

def p_mainRule(p):
	'''mainRule :  NUMBER SIZE COLOR KIND'''
	db.addElement(p)

def p_actionRule(p):
	'''actionRule :  ACTION'''
	if p[1] == "db":
		db.showDatabase()
	else:
		db.showDatabaseHumanReadable()

def p_error(p):
	print("^--------------- Failure")

Uruchomienie yacc

import ply.yacc as yacc

# Order of rules
# ...

# Definitions for rules
# ...


# Create parser
parser = yacc.yacc()

Start parsera

while True:
    try:
        s = input('~$ ')   # Use raw_input on Python 2
    except EOFError:
        break
    parser.parse(s)

Krótkie przedstawienie działania przykładowej aplikacji

Podsumowanie

Made with Slides.com