Analizator leksykalny

Pozostałe układy mikrokontrolerów, układy peryferyjne i inne, nie mieszczące się w powyższych kategoriach.
Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Analizator leksykalny

Postautor: gaweł » niedziela 25 cze 2017, 01:08

Analizator leksykalny i syntaktyczny

w wielu przypadkach w rozwiązaniach urządzeń z mikrokontrolerami przydatnym jest możliwość porozumienia z mikrokontrolerem. Swoisty dialog operatora/użytkownika z urządzeniem wymaga jednak stworzenia odpowiedniego języka. Taki kanał wymiany informacji pozwala na szerokie możliwości określenia szczegółów synergii ze stroną przeciwną. Podobną funkcjonalność może zapewnić odpowiednio rozbudowany frontpanel, chociaż właściwie należy uznać, że każdy taki panel będzie zbyt ubogi w swoich możliwościach w stosunku do realizacji prawdziwego dialogu. Jak dialog... to normalnym jest, że niezbędna jest jakaś techniczna platforma porozumienia. W przypadku komunikacji międzyludzkiej taką platformą jest narząd mowy i słuchu (czasem telepatia :) ). W przypadku urządzeń elektronicznych takim odpowiednikiem jest kanał transmisji szeregowej. Pozwala on na przesyłanie w obie strony ciągu znaków, taki odpowiednik ludzkich głosek. Z głosek (czyli liter) możliwe jest utworzenie fraktalnie wyższej warstwy, czyli wyrazów i zdań. Bez zbędnego rozbudowywania frontpaneli, przekazywanie via serial informacji daje nieograniczone możliwości. Można zaryzykować stwierdzenie, że potęga słowa jest nieskończona.
Podstawą takiej komunikacji jest odpowiedni język. Skoro język... to mamy zdania. Występuje tu operacja budowy zdań, do ich budowy niezbędne są kolejne detale. Takimi detalami są rzecz jasna wyrazy, liczby i różne znaki dodatkowe. Rozkładając proces analizy zdań na poszczególne elementy mamy przede wszystkim analizę leksykalną i analizę syntaktyczną. Analiza leksykalna jest zagadnieniem dotyczącym budowy poszczególnych składowych przekazywanych komunikatów. Nie trzeba nikogo przekonywać, że wyraz normalnie składa się z liter (w komunikacji z urządzeniami można rozszerzyć normy i ustalić, że wyraz jest ciągiem liter lub cyfr zaczynającym się od litery). Podobnie liczby składają się z ciągu znaków będących cyframi z ewentualnym dodatkiem znaku kropki jako separatora pomiędzy częścią całkowitą i ułamkową liczby (zakładając, że jest mowa jedynie o liczbach w systemie dziesiętnym). Reasumując, analiza leksykalna jest zogniskowana na budowie części składowych zdania jakimi są wyrazy i liczby natomiast nie zajmuje się analizą syntaktyczną (analizą składni zdania).
Przedstawiony moduł stanowi narzędzie do analizy leksykalnej. Jest skonstruowany w formie „otwartego” modułu. Ta „otwartość” przede wszystkim wyraża się tym, że moduł nie posiada własnej wbudowanej instancji a posiłkuje się instancją „obcą”. Pozwala to na utworzenie fraktalnie wyższych poziomów analizy, jednak każdy taki poziom jest oparty o analizę leksykalną.
Moduł „eksportuje” następujące typy i funkcje:

Kod: Zaznacz cały

typedef enum { LexicNoSy                 ,      // symbol nierozpoznany
               LexicEndFileSy            ,      // napotkano koniec pliku
               LexicEndLineSy            ,      // napotkano koniec wiersza
               LexicEqSy                 ,      // napotkano znak '='
               LexicPlusSy               ,      // napotkano znak '+'
               LexicMinusSy              ,      // napotkano znak '-'
               LexicMultSy               ,      // napotkano '*'
               LexicDivSy                ,      // napotkano '/'
               LexicLTSy                 ,      // napotkano '<'
               LexicGTSy                 ,      // napotkano '>'
               LexicLESy                 ,      // napotkano '<='
               LexicGESy                 ,      // napotkano '>='
               LexicAndSy                ,      // napotkano '&'
               LexicLParentSy            ,      // napotkano '('
               LexicRParentSy            ,      // napotkano ')'
               LexicLBrackSy             ,      // napotkano '['
               LexicRBrackSy             ,      // napotkano ']'
               LexicCommaSy              ,      // napotkano ','
               LexicPointSy              ,      // napotkano '.'
               LexicColonSy              ,      // napotkano ':'
               LexicSemiColonSy          ,      // napotkano ';'
               LexicHashSy               ,      // napotkano '#'
               LexicCConstSy             ,      // naptkano stala calkowita
               LexicRConstSy             ,      // napotkano stala rzeczywista
               LexicSConstSy             ,      // napotkano stala tekstowa
               LexicIdentSy } LexicSymbolType ; // napotkano identyfikator
Typ wyliczeniowy, który pozwala zidentyfikować ostatnio wczytany (rozpoznany w analizowanym zdaniu) element leksykalny. Generalnie znaczenie poszczególnych wartości tego typu powinno być oczywiste, jednak wybrane elementy mogą wymagać drobnego komentarza.
  • LexicNoSy – oznacza, że analizator „mówi”, że nie rozumie co to jest,
  • LexicEndLineSy – (taki sztuczny element zdania) oznacza, że analizator dotarł do końca wiersza, czasami przydatne jest traktowanie końca linii za element leksykalny, czasami jest przydatna swoista przezroczystość końca wiersza (więcej przy okazji rozpatrywaniu pojęcie sektora),
  • LexicEndFileSy – (taki sztuczny element zdania) oznacza, że analizator dotarł do końca pliku (końca zbioru wierszy, więcej przy okazji rozpatrywaniu pojęcie sektora),
  • LexicCConstSy – oznacza, że analizator łyknął dziesiętną liczbę całkowitą,
  • LexicRConstSy – oznacza, że analizator wczytał dziesiętną liczbę zmiennoprzecikową,
  • LexicSConstSy – oznacza, że analizator rozpoznał stałą tekstową, jako dowolny łańcuch znaków ujęty w apostrofy (jako apostrof uważany jest znak ' lub ", z tym, że apostrof zamykający musi być identyczny jak otwierający),
  • LexicIdentSy – oznacza, że analizator napotkał wyraz literowy (jako ciąg liter lub cyfr zaczynający się od litery), jednak nie rozpatruje znaczenia napotkanego wyrazu (to jest domena analizy syntaktycznej).

Kod: Zaznacz cały

typedef uint8_t SpellingType [ 16 ] ;
typedef uint8_t InpStringType [ 42 ] ;
  • SpellingType – typ reprezentujący zmienną przechowującą „obraz” ostatnio wczytanego elementu leksykalnego (w szczególnym wypadku jest „tekst wyrazu literowego”),
  • InpStringType – typ reprezentujący zmienną przechowująca wartość stałej łańcuchowej (bez użytych znaków apostrofów).

Kod: Zaznacz cały

typedef void ( * ListServiceProcT ) ( uint8_t /* Ch        */ ,
                                      void *  /* CallParam */ ) ;
  • typ „metody” związanej z raportowaniem analizowanych wierszy.

Kod: Zaznacz cały

struct _LexicalAnalysisInstanceType ;
typedef struct _LexicalAnalysisInstanceType * PtrLexicalAnalysisInstanceType ;
typedef uint16_t ( * LexicalAnalysisServPType ) ( PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
typedef void ( * LexicalAnalysisRaportPType ) ( PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
typedef struct _LexicalAnalysisInstanceType {
                 void *                       CallParam ;
                 ListServiceProcT             ListService ;
                 LexicalAnalysisRaportPType   RaportService ;
                 LexicalAnalysisServPType     GetSectorServ ;
                 uint8_t *                    DataSector ;
                 uint8_t *                    SectorCh ;
                 uint8_t *                    BeginOfLine ;
                 uint8_t *                    EndOfLine ;
                 uint8_t                      RealEnable ;
                 uint8_t *                    CurrChar ;
                 uint8_t                      LineChar ;
                 uint8_t                      LineChar2 ;
                 uint8_t                      AutoReadLineFlag ;
                 uint8_t                      AutoEOFAnswer ;
                 uint16_t                     SectorChPos ;
                 uint32_t                     CInpValue ;
                 uint16_t                     LineCounter ;
                 uint16_t                     SectorSize ;
                 uint16_t                     LineSize ;
                 double                       RInpValue ;
                 uint16_t                     SpeelCt ;
                 SpellingType                 InpSpelling ;
                 InpStringType                SInpValue ;
                 uint16_t                     ErrCodes [ MaxErr ] ;
                 SpellingType                 ErrSpell [ MaxErr ] ;
                 uint8_t                      ErrIndex ;
                 uint8_t                      EndOfLineReached ;
                 uint8_t                      EndOfFileReached ;
                 uint8_t                      ErrorPresent ;
                 uint8_t                      GlobalErrorPresent ;
               } LexicalAnalysisInstanceType ;
Moduł posługuje się pojęciem sektora, czyli zbiorem wierszy rozdzielonych znakami Cr i Lf (sam znak Cr również powinien zadziałać). W analizowanych danych może wystąpić znak tabulacji (Tab), który będzie traktowany jak znak odstępuj (spacji). W trakcie analizy z sektora „wydzielane” są poszczególne wiersze, które podlegają analizie. W szczególnym przypadku sektor może składać się z jednego wiersza. Analiza może byś realizowana z zatrzymaniem na końcu każdego wiersza, gdzie „czytanie na siłę elementów” zawsze zwraca informację, że został napotkany koniec wiersza. Przydatne w sytuacjach, gdzie koniec wiersza ma określone znaczenie, jak w przypadku języka assembler → koniec wiersza oznacza również koniec instrukcji (nie ma kontynuacji w następnych wierszach). Innym wariantem jest automatyczne przejście do kolejnego wiersza (wtedy nie jest sygnalizowany koniec wiersza jako element leksykalny). Przydatne w przypadku języka C, PASCAL → koniec wiersza nie oznacza końca instrukcji i kolejnych wierszach mogą być zapisy kontynuacyjne).
Typ instancji używanej w module. Ciało instancji należy utworzyć w warstwie wyższej. Z pól instancji wybrane mają następujące znaczenie:
  • void * CallParam – wskaźnik do dowolnej struktury, jako dodatkowe dane z warstwy wyższej przekazywane do wybranych metod,
  • ListServiceProcT ListService – metoda do generowania pojedynczego wiersza raportu analizy leksykalnej,
  • LexicalAnalysisRaportPType RaportService – metoda do generowania raportu z analizy, w standardowej implementacji jest przedrukiem analizowanych wierszy z dodaniem z przodu numeru wiersza,
  • LexicalAnalysisServPType GetSectorServ – metoda do wczytania kolejnego sektora analizowanego tekstu,
  • uint8_t * DataSector – wskaźnik do obszaru analizowanego sektora,
  • uint16_t SectorSize – wielkość obszaru sektora w znakach (liczba znaków wskazywanych przez wskaźnik DataSector),
  • uint8_t * SectorCh – wskaźnik w obszarze sektora,
  • uint8_t * BeginOfLine – wskaźnik w obszarze sektora określający początek analizowanego wiersza,
  • uint8_t * EndOfLine – wskaźnik w obszarze sektora określający koniec analizowanego wiersza,
  • uint8_t RealEnable – flaga określająca, czy analizator będzie rozpatrywał liczby zmiennoprzecienkowe (należy sterować tą flagą w przypadku, gdy spodziewane jest wczytanie klasycznego zapisu adresu IP jako cztery liczby rozdzielone trzema znakami kropki),
  • uint8_t * CurrChar – wskaźnik w obrębie wiersza, gdzie „znajduje się” aktualnie analizator leksykalny,
  • uint8_t AutoReadLineFlag – flaga automatycznego przejścia do kolejnego wiersza (dla TRUE), lub „zawiśnięciu” na każdym końcu wiersza (FALSE),
  • uint32_t CInpValue – wczytana liczba całkowita (przechowywana jako liczba 32-bitowa),
  • double RInpValue – wczytana liczba zmiennoprzecinkowa podwójnej precyzji,
  • InpStringType SInpValue – wczytana stała łańcuchowa (bez znaków apostrofów),
  • SpellingType InpSpelling – „obraz” bieżąco wczytanego elementu leksykalnego,
  • uint16_t ErrCodes [ MaxErr ] – zgłoszone dla wiersza kody błędów,
  • SpellingType ErrSpell [ MaxErr ] – „synchronicznie” z ErrCodes „obraz” syntaktycznych elementów, które wygenerowały błąd,
  • uint8_t ErrIndex – liczba błędów zgłoszonych dla wiersza (zerowana po każdym wczytaniu kolejnego wiersza)
  • uint8_t ErrorPresent – flaga określająca, czy w danym wierszu wystąpiły błędy (zerowana po każdym wczytaniu kolejnego wiersza),
  • uint8_t GlobalErrorPresent – flaga określająca, czy w danym pliku (zbiorze sektorów → zbiorze wierszy) wystąpiły błędy (czy wystąpił błąd gdziekolwiek).

Kod: Zaznacz cały

uint8_t ReadLine ( PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
  • funkcja do wczytania kolejnego wiersza z obszaru sektora,

Kod: Zaznacz cały

void AnalError ( uint16_t                       /* ErrorNo                 */ ,
                 PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
  • funkcja do zgłoszenia kodu błędu (do ErrSpell zostanie przeniesiona bieżąca zawartość Spelling),

Kod: Zaznacz cały

void AnalLCError ( uint16_t                       /* ErrorCode               */ ,
                   uint32_t                       /* LCValue                 */ ,
                   PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
void AnalCError ( uint16_t                       /* ErrorCode               */ ,
                  uint16_t                       /* CValue                  */ ,
                  PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
  • funkcja do zgłoszenia kodu błędu (w ErrSpell zostanie umieszczona wartość CValue/LCValue),

Kod: Zaznacz cały

void AnalSError ( uint16_t                       /* ErrorCode               */ ,
                  uint8_t *                      /* SValue                  */ ,
                  PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
  • funkcja do zgłoszenia kodu błędu (w ErrSpell zostanie umieszczona wartość SValue),

Kod: Zaznacz cały

LexicSymbolType ReadSymbol ( PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
  • funkcja do wczytania kolejnego elementu leksykalnego, wartość funkcji identyfikuje element leksykalny,

Kod: Zaznacz cały

void CheckEndOfLine ( PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ,
                      uint16_t                       /* ErrorCode               */ ) ;
  • funkcja do zgłoszenia kodu błędu dla każdego elementu leksykalnego występującego przed końcem wiersza,

Kod: Zaznacz cały

LexicSymbolType AcceptSymbol ( PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ,
                               LexicSymbolType                /* ExpectedSymbol          */ ,
                               uint16_t                       /* ErrorCode               */ ) ;
  • funkcja do wczytania kolejnego elementu leksykalnego i zgłoszenia błędy w sytuacji, gdy wczytany element leksykalny był inny niż oczekiwany,

Kod: Zaznacz cały

void OpenSectorAnalyser ( PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ,
                          uint8_t *                      /* LinesBuffer             */ ,
                          uint16_t                       /* LinesSize               */ ,
                          ListServiceProcT               /* TraceListService        */ ,
                          void *                         /* CallParam               */);
  • funkcja do otwarcia analizy leksykalnej, ustawia wartości początkowe pól instancji, podłącza w instancji „standardowe” metody, podłącza pod analizator sektor obszaru /parametr LinesBuffer/ o określonej wielkości /parametr LinesSize/, wczytuje z sektora pierwszy wiersz.

Kod: Zaznacz cały

void CloseSectorAnalyser ( PtrLexicalAnalysisInstanceType /* LexicalAnalysisInstance */ ) ;
  • funkcja do zamknięcia analizy leksykalnej dla danego sektora.
Ostatnio zmieniony niedziela 25 cze 2017, 17:02 przez gaweł, łącznie zmieniany 1 raz.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
j23
Expert
Expert
Posty: 506
Rejestracja: czwartek 08 paź 2015, 18:40

Re: Analizator leksykalny

Postautor: j23 » niedziela 25 cze 2017, 02:32

Dziękuję Kolego Gaweł za bardzo ciekawe wytłumaczenie - z przykładami kodu. Od siebie mogę dodać, że istnieje jeszcze coś takiego jak uniwersalna struktura słownikowa. Jest to bardzo dobrze opisane w książce Pana Piotra Wróblewskiego "Algorytmy, struktury danych i techniki programowania" (na stronach Heliona powinny być kody źródłowe do ściągnięcia ;) )
Ogólnie chodzi o to, że żeby "nauczyć", albo kazać komputerowi zapamiętać wyraz do słownika, zdanie, etc. wykorzystuje się strukturę drzewiastą, np.
KR-
    |-AWIEC
    |-O-
          |-SNO
          |-K-
                |-ODYL
                |-US
...i tak to wyraz może być dzielony na sylaby, a te z kolei zapamiętywane w kolejnych komórkach pamięci, lub zapamiętany wskaźnik na komórkę pamięci. Tam w książce to jest co prawda opis dotyczący języka C++, ale w tym wypadku przypuszczam, że można to z powodzeniem stosować w C.
Jest chyba jedna wada tej metody, mianowicie taka, że algorytm stosowany w niej jest typu rekurencyjnego, więc chyba trzeba by dodatkowo opracować jakiś mechanizm kontroli pamięci w celu zabezpieczenia przed przepełnieniem stosu, albo przepełnieniem innego rodzaju pamięci.

A tutaj poniżej w linku kilku programistów pracowało nad USS w języku Pascal:
https://4programmers.net/Forum/Delphi_Pascal/119433-Uniwersalna_Struktura_Slownikowa_Pascal?p=425336#id425336

Pozdrawiam! j23 Jarek
Internet łączy ludzi, którzy dzielą się swoimi zainteresowaniami, pomysłami i potrzebami, bez względu na geograficzne (przeciwności).
BOB TAYLOR, PARC

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Analizator leksykalny

Postautor: gaweł » niedziela 25 cze 2017, 02:50

Analizator leksykalny i syntaktyczny przykład 1
synt01_ilu00.jpg
Załóżmy, że mamy urządzenie z mikrokontrolerem, z którym via serial istnieje możliwość komunikacji. „Gramatyka” języka do porozumień jest określona następująco (możliwe warianty zdań):
  • display set all
  • display clear all
  • display set bit <numer>
    gdzie <numer> jest liczbą całkowitą z zakresu 0 .. 7
  • display clear bit <numer>
    gdzie <numer> jest liczbą całkowitą z zakresu 0 .. 7
  • display set bin <liczba>
    gdzie <liczba> jest liczbą całkowitą z zakresu 0 .. 255
  • display clear bin <liczba>
    gdzie <liczba> jest liczbą całkowitą z zakresu 0 .. 255
  • display set char "<znak>"
    gdzie "<znak>" jest jednoznakową stałą tekstową (znak " można zamienić na ')
  • display clear char "<znak>"
    gdzie "<znak>" jest jednoznakową stałą tekstową (znak " można zamienić na ')
Do eksperymentów zastosowany został Moduł M32. Zapis „display set” oznacza żądanie zaświecenia diody LED, zapis „display clear” oznacza żądanie zgaszenia diody LED. Z dalszej analizy zdania wynikają szczegółowe informacje:
  • all – oznacza wszystkie diody LED (8 sztuk),
  • bit <numer> – dotyczy bitu o podanym numerze,
  • bin <liczba> – dotyczy bitów, w których podana <liczba> ma jedynki,
  • char '<znak>' – dotyczy bitów, w których podany znak <znak> ma jedynki.
Po uruchomieniu urządzenia, komunikuje się ono z użytkownikiem „przypiętym” do emulatora terminala. Na dzień dobry wyświetlany jest następujący tekst:
synt01_ilu02.png
zachęcający do napisania polecenia.
Przykładowo, polecenie: display set all
synt01_ilu03.png
oznaczające zapalenie wszystkich LED'ów, skutkuje następująco:
synt01_ilu04.jpg
polecenie: display clear all
synt01_ilu05.png
oznaczające zgaszenie wszystkich LED'ów, skutkuje następująco:
synt01_ilu06.jpg
Polecenie" display set char '*'
synt01_ilu07.png
nak * ma kod 2A hex, 00101010 bin → zapala 3 diody LED, skutkuje następująco:
synt01_ilu08.jpg
Polecenie: display set bit 7
synt01_ilu09.png
Oznacza zapalenie diody LED odpowiadającej bitowi 7, skutkuje następująco:
synt01_ilu10.jpg
Polecenie" display clear bin 170
synt01_ilu11.png
Oznacza zgaszenie diód LED odpowiadających liczbie 170 dec = AA hex = 10101010 bin, skutkuje następująco:
synt01_ilu12.jpg
Błędne polecenie nie implikuje żadnych działań.
synt01_ilu13.png

Program do obsługi jest następujący:

Kod: Zaznacz cały

(…)
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "lexicalmodule.h"
#include "stringsmodule.h"

#define FALSE                           0
#define TRUE                            1
#define NIL                             ( void * ) 0

#define Null                            0x00
#define Cr                              0x0D
#define Lf                              0x0A
#define Bs                              0x08
#define Space                           0x20

#define LEDPort                         PORTB
#define LEDDirPort                      DDRB

#define USART_Speed                     47   // USART BAUD Rate Generator fosc=7.3728 MHz , 9600 bps

#define nop() __asm__ __volatile__ ("nop")

#define IdleState                       0
#define BusyState                       1

#define TXDBuffSize                     64
#define RXDBuffSize                     16

typedef struct { uint8_t CycFr ;
                 uint8_t CycTo ;
                 uint8_t State ;
                 uint8_t Buffer [ TXDBuffSize ] ;
               } TXDRecT ;
typedef struct { uint8_t CycFr ;
                 uint8_t CycTo ;
                 uint8_t Buffer [ RXDBuffSize ] ;
               } RXDRecT ;

static volatile TXDRecT TXDRec ;
static volatile RXDRecT RXDRec ;
static uint8_t LEDData ;

#define CommandBufferSize               64

static LexicalAnalysisInstanceType LexicalAnalysisInstance ;
static uint8_t CommandBuffer [ CommandBufferSize + 1 ] ;
static uint8_t CommandBufferIndex ;


static uint8_t HelloTxt [ ] PROGMEM     = "\r\nCzesc koles z www.microgeek.eu:\r\nNapisz polecenie\r\n" ;
static uint8_t ErrorMessage [ ] PROGMEM = "Bledne polecenie\r\n\r\n" ;

#define ErrorCode                       100

#define DictionaryWordSize              12

typedef uint8_t SyntaxWordType [ DictionaryWordSize ] ;
typedef enum { DisplaySy                  ,
               SetSy                      ,
               ClearSy                    ,
               AllSy                      ,
               CharSy                     ,
               BitSy                      ,
               BinarySy                   ,
               UnknownWord                } SyntaxSymbolT ;

typedef struct {
                 SyntaxWordType           WordText ;
                 SyntaxSymbolT            WordSymbol ;
               } DictionaryRecT ;

#define DictionarySize                  7

static DictionaryRecT Dictionary [ DictionarySize ] PROGMEM =
  {
/*  0 */ { "DISPLAY    " , DisplaySy } ,
/*  1 */ { "SET        " , SetSy } ,
/*  2 */ { "CLEAR      " , ClearSy } ,
/*  3 */ { "ALL        " , AllSy } ,
/*  4 */ { "CHAR       " , CharSy } ,
/*  5 */ { "BIT        " , BitSy } ,
/*  6 */ { "BIN        " , BinarySy } ,
  } ;




SIGNAL ( SIG_UART_RECV )
{
  uint8_t RecVCh ;
  /*-------------------------------------------------------------------------*/
  RecVCh = UDR ;
  RXDRec . Buffer [ RXDRec . CycTo ] = RecVCh ;
  RXDRec . CycTo ++ ;
  if ( RXDRec . CycTo >= RXDBuffSize )
    RXDRec . CycTo = 0 ;
} /* SIG_USART_RECV */


SIGNAL ( SIG_UART_TRANS )
{
  /*-------------------------------------------------------------------------*/
  if ( TXDRec . CycFr == TXDRec . CycTo )
  {
    TXDRec . State = IdleState ;
  } /* if ... */
  else
  {
    UDR = TXDRec . Buffer [ TXDRec . CycFr ] ;
    TXDRec . CycFr ++ ;
    if ( TXDRec . CycFr >= TXDBuffSize )
      TXDRec . CycFr = 0 ;
  } /* if ... else */ ;
} /* SIG_USART_TRANS */


static void USARTSoftwareInit ( void )
{
  /*-------------------------------------------------------------------------*/
  RXDRec . CycFr = 0 ;
  RXDRec . CycTo = 0 ;
  TXDRec . CycFr = 0 ;
  TXDRec . CycTo = 0 ;
  TXDRec . State = IdleState ;
} /* USARTSoftwareInit */


static void SendSerial ( uint8_t SerialCh )
{
  uint8_t NextInx ;
  /*-------------------------------------------------------------------------*/
  cli ( ) ;
  if ( TXDRec . State == IdleState )
  {
    TXDRec . State = BusyState ;
    UDR = SerialCh ;
    sei ( ) ;
  } /* if ... */
  else
  {
    for ( ; ; )
    {
      NextInx = TXDRec . CycTo + 1 ;
      if ( NextInx >= TXDBuffSize )
        NextInx = 0 ;
      if ( NextInx != TXDRec . CycFr )
        break ;
      sei ( ) ;
      nop ( ) ;
      nop ( ) ;
      cli ( ) ;
    } /* for */ ;
    TXDRec . Buffer [ TXDRec . CycTo ] = SerialCh ;
    TXDRec . CycTo ++ ;
    if ( TXDRec . CycTo >= TXDBuffSize )
      TXDRec . CycTo = 0 ;
    sei ( ) ;
  } /* if ... else */ ;
} /* SendSerial */


static void SendSerialFlashTxt ( uint8_t * String )
{
  uint8_t Data ;
  /*-------------------------------------------------------------------------*/
  for ( ; ; )
  {
    Data = pgm_read_byte_near ( String ) ;
    if ( Data )
      SendSerial ( Data ) ;
    else
      break ;
    String ++ ;
  } /* for */ ;
} /* SendSerialFlashTxt */


static void SendSerialTxt ( uint8_t * String )
{
  /*-------------------------------------------------------------------------*/
  while ( * String )
  {
    SendSerial ( * String ++ ) ;
  } /* for */ ;
} /* SendSerialTxt */


static void SendNewLine ( void )
{
  /*-------------------------------------------------------------------------*/
  SendSerial ( Cr ) ;
  SendSerial ( Lf ) ;
} /* SendNewLine */


static uint8_t SerialDataPresent ( void )
{
  /*-------------------------------------------------------------------------*/
  if ( RXDRec . CycFr == RXDRec . CycTo )
    return ( FALSE ) ;
  else
    return ( TRUE ) ;
} /* SerialDataPresent */


static uint8_t GetSerial ( void )
{
  uint8_t Ch ;
  /*-------------------------------------------------------------------------*/
  Ch = RXDRec . Buffer [ RXDRec . CycFr ] ;
  RXDRec . CycFr ++ ;
  if ( RXDRec . CycFr >= RXDBuffSize )
    RXDRec . CycFr = 0 ;
  return Ch ;
} /* GetSerial */


static void HardwareInit ( void )
{
  /*-------------------------------------------------------------------------*/
  UCSRA = 0 ;
//      UART Control and Status Register A
//      MCPM : Multi-processor Communication Mode
//      U2X : Double speed
//      PE : Parity Error (tylko odczyt)
//      DOR : Data Overrun (tylko odczyt)
//      FE : Framing Error (tylko odczyt)
//      UDRE : USART Data Register Empty (tylko odczyt)
//      TXC : Transmit Complete
//      RXC : Receive Complete (tylko odczyt)
  UCSRB = ( 1 << RXCIE ) | ( 1 << TXCIE ) | ( 1 << RXEN ) | ( 1 << TXEN ) ;
//      USART Control and Status Register B
//      TXD8 : Transmit Data Bit 8
//      RXB8 : Receive Data Bit 8
//      UCSZ2 : Character Size
//      TXEN : Transmitter Enable
//      RXEN : Receiver Enable
//      UDRIE : USART Data Register Empty Interrupt Enable
//      TXCIE : TX Complete Interrupt Enable
//      RXCIE : RX Complete Interrupt Enable
  UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 ) ;
//      UART Control and Status Register C
//      UCPOL : USART Clock Polarity
//      UCSZ0 : USART Character Size
//      UCSZ1 : USART Character Size
//      USBS : USART Stop Bit Select
//      UMP0 : USART Parity Mode
//      UPM1 : USART Parity Mode
//      UMSEL : USART Mode Select
//      URSEL : USART Register Select
  UBRRH = ( uint8_t ) ( ( USART_Speed >> 8 ) & 0xFF ) ;
  UBRRL = ( uint8_t ) ( USART_Speed & 0xFF ) ;
} /* HardwareInit */


static void EnvirInit ( void )
{
  /*-------------------------------------------------------------------------*/
  LEDDirPort = 0xFF ;
  LEDPort = 0 ;
} /* EnvirInit */


static void SoftwareInit ( void )
{
  /*-------------------------------------------------------------------------*/
  USARTSoftwareInit ( ) ;
  CommandBufferIndex = 0 ;
  LEDData = 0 ;
} /* SoftwareInit */


static SyntaxSymbolT SyntaxDecodeWord ( PtrLexicalAnalysisInstanceType LexicalAnalysisInstance )
{
  uint16_t Loop ;
  uint8_t IntLoop ;
  SyntaxWordType StrToComp ;
  uint8_t Ch1 ;
  uint8_t Ch2 ;
  uint8_t CompareOK ;
  DictionaryRecT DictElement ;
  uint16_t DictionaryArray ;
  /*--------------------------------------------------------------------------*/
  for ( Loop = 0 ; Loop < DictionaryWordSize ; Loop ++ )
  {
    StrToComp [ Loop ] = Cap ( LexicalAnalysisInstance -> InpSpelling [ Loop ] ) ;
  } /* for */ ;
  StrToComp [ DictionaryWordSize - 1 ] = Null ;
  DictionaryArray = ( uint16_t ) & Dictionary ;
  for ( Loop = 0 ; Loop < DictionarySize ; Loop ++ )
  {
    GetPGMBlock ( & DictElement , DictionaryArray , sizeof ( DictionaryRecT ) ) ;
    DictionaryArray += sizeof ( DictionaryRecT ) ;
    CompareOK = TRUE ;
    for ( IntLoop = 0 ; IntLoop < DictionaryWordSize ; IntLoop ++ )
    {
      Ch1 = StrToComp [ IntLoop ] ;
      Ch2 = DictElement . WordText [ IntLoop ] ;
      if ( Ch1 != Ch2 )
      {
        CompareOK = FALSE ;
        break ;
      } /* if */ ;
    } /* for */ ;
    if ( CompareOK )
      return ( DictElement . WordSymbol ) ;
  } /* for */ ;
  return ( UnknownWord ) ;
} /* SyntaxDecodeWord */


static void DisplayErrors ( PtrLexicalAnalysisInstanceType LexicalAnalysisInstance )
{
  /*-------------------------------------------------------------------------*/
  SendSerialFlashTxt ( ErrorMessage ) ;
} /* DisplayErrors */


static void ExecuteCommand ( void )
{
//
// display set all
// display clear all
// display set bit <numer>
// display clear bit <numer>
// display set bin <liczba>
// display clear bin <liczba>
// display set char "<znak>"
// display clear char "<znak>"
//
  LexicSymbolType LexicSymbol ;
  SyntaxSymbolT SyntaxSymbol ;
  uint8_t SetOperation ;
  uint8_t Operand ;
  uint8_t Tmp ;
  uint8_t AllOperand ;
  /*-------------------------------------------------------------------------*/
  SetOperation = FALSE ;
  AllOperand = FALSE ;
  OpenSectorAnalyser ( & LexicalAnalysisInstance , CommandBuffer , CommandBufferIndex , NIL , NIL ) ;
  LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ErrorCode ) ;
  if ( LexicSymbol == LexicIdentSy )
  {
    SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
    if ( SyntaxSymbol == DisplaySy )
    {
      LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ErrorCode ) ;
      if ( LexicSymbol == LexicIdentSy )
      {
        SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
        switch ( SyntaxSymbol )
        {
          case SetSy            :
            SetOperation = TRUE ;
            break ;
          case ClearSy          :
            SetOperation = FALSE ;
            break ;
          default               :
            AnalError ( ErrorCode , & LexicalAnalysisInstance ) ;
        } /* switch */ ;
        LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ErrorCode ) ;
        if ( LexicSymbol == LexicIdentSy )
        {
          SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
          switch ( SyntaxSymbol )
          {
            case AllSy           :
              AllOperand = TRUE ;
              break ;
            case CharSy          :
              LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicSConstSy , ErrorCode ) ;
              if ( StrLen ( LexicalAnalysisInstance . SInpValue ) != 1 )
              {
                AnalSError ( ErrorCode , LexicalAnalysisInstance . SInpValue , & LexicalAnalysisInstance ) ;
              } /* if */ ;
              Operand = LexicalAnalysisInstance . SInpValue [ 0 ] ;
              break ;
            case BitSy           :
              LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicCConstSy , ErrorCode ) ;
              if ( LexicalAnalysisInstance . CInpValue > 7 )
              {
                AnalLCError ( ErrorCode , LexicalAnalysisInstance . CInpValue , & LexicalAnalysisInstance ) ;
              } /* if */ ;
              Tmp = ( ( uint8_t ) LexicalAnalysisInstance . CInpValue ) & 0x07 ;
              Operand = ( 1 ) << Tmp ;
              break ;
            case BinarySy        :
              LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicCConstSy , ErrorCode ) ;
              if ( LexicalAnalysisInstance . CInpValue > 255 )
              {
                AnalLCError ( ErrorCode , LexicalAnalysisInstance . CInpValue , & LexicalAnalysisInstance ) ;
              } /* if */ ;
              Operand = ( uint8_t ) LexicalAnalysisInstance . CInpValue ;
              break ;
            default              :
              AnalError ( ErrorCode , & LexicalAnalysisInstance ) ;
          } /* switch */ ;
          CheckEndOfLine ( & LexicalAnalysisInstance , ErrorCode ) ;
        } /* if */ ;
      } /* if */ ;
    } /* if ... */
    else
    {
      AnalError ( ErrorCode , & LexicalAnalysisInstance ) ;
    } /* if ... else */ ;
  } /* if */ ;
  if ( ErrorsPresent ( & LexicalAnalysisInstance ) )
  {
    DisplayErrors ( & LexicalAnalysisInstance ) ;
  } /* if ... */
  else
  {
    if ( SetOperation )
    {
      if ( AllOperand )
        LEDData = 0xFF ;
      else
        LEDData = LEDData | Operand ;
    } /* if ... */
    else
    {
      if ( AllOperand )
        LEDData = 0 ;
      else
        LEDData = LEDData & ( ~ Operand ) ;
    } /* if ... else */ ;
    LEDPort = LEDData ;
  } /* if ... else */ ;
  CloseSectorAnalyser ( & LexicalAnalysisInstance ) ;
} /* ExecuteCommand */


static void RedispBuffer ( void )
{
  uint8_t Loop ;
  /*-------------------------------------------------------------------------*/
  SendSerial ( Cr ) ;
  for ( Loop = 0 ; Loop < CommandBufferSize ; Loop ++ )
    SendSerial ( Space ) ;
  SendSerial ( Cr ) ;
  SendSerialTxt ( CommandBuffer ) ;
} /* RedispBuffer */


static void ProcessChar ( uint8_t Ch )
{
  /*-------------------------------------------------------------------------*/
  if ( Ch == Bs )
  {
    if ( CommandBufferIndex )
    {
      CommandBufferIndex -- ;
      CommandBuffer [ CommandBufferIndex ] = Null ;
      RedispBuffer ( ) ;
    } /* if */ ;
    return ;
  } /* if */ ;
  if ( Ch == Cr )
  {
    SendNewLine ( ) ;
    SendNewLine ( ) ;
    ExecuteCommand ( ) ;
    CommandBuffer [ 0 ] = Null ;
    CommandBufferIndex = 0 ;
    return ;
  } /* if */ ;
  if ( Ch >= Space )
  {
    if ( CommandBufferIndex < CommandBufferSize )
    {
      CommandBuffer [ CommandBufferIndex ] = Ch ;
      CommandBufferIndex ++ ;
      CommandBuffer [ CommandBufferIndex ] = Null ;
    } /* if */ ;
    RedispBuffer ( ) ;
  } /* if */ ;
} /* ProcessChar */



int main ( void )
{
  /*-------------------------------------------------------------------------*/
  HardwareInit ( ) ;
  EnvirInit ( ) ;
  SoftwareInit ( ) ;
  sei ( ) ;
  SendNewLine ( ) ;
  SendSerialFlashTxt ( HelloTxt ) ;
  SendNewLine ( ) ;
  SendNewLine ( ) ;
  for ( ; ; )
  {
    if ( SerialDataPresent ( ) )
    {
      ProcessChar ( GetSerial ( ) ) ;
    } /* if */ ;
  } /* for */ ;
  return ( 0 ) ;
} /* main */


Załączniki: kompletny projekt w AVR STUDIO [update: 25.VI.2017].
syntax1.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Ostatnio zmieniony niedziela 25 cze 2017, 17:31 przez gaweł, łącznie zmieniany 3 razy.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Analizator leksykalny

Postautor: gaweł » niedziela 25 cze 2017, 03:10

j23 pisze:Jest chyba jedna wada tej metody, mianowicie taka, że algorytm stosowany w niej jest typu rekurencyjnego,

Czasami jest to wada, czasami nie jest wadą (wszystko jest relatywne). Jest metoda zamiany algorytmów rekurencyjnych na iteracyjne, ale w gruncie rzeczy, zżerają również zasoby kompa (pamięć). Podejście rekurencyjne często daje bardziej klarowny zapis algorytmu, Takim klasycznym przykładem jest rekurencyjna analiza wyrażenia arytmetycznego. Przy okazji daje ona kod w notacji odwrotnej polskiej pozwalający realizować obliczenie (z punktu widzenia kompilatorów języka → wygenerować kod do obliczania).

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Analizator leksykalny

Postautor: gaweł » niedziela 25 cze 2017, 12:48

j23 pisze:Ogólnie chodzi o to, że żeby "nauczyć", albo kazać komputerowi zapamiętać wyraz do słownika, zdanie, etc. wykorzystuje się strukturę drzewiastą, np.

Struktury drzewiaste to fajny wynalazek. Odmianą tej filozofii są B Drzewa (B-TREE) podstawa algorytmów rozwiązań bazodanowych (może o tym kiedyś napiszę).

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Analizator leksykalny

Postautor: gaweł » niedziela 25 cze 2017, 14:06

Analizator leksykalny i syntaktyczny
komentarz do przykładu 1


Program komunikuje się z otoczeniem poprzez interfejs szeregowy. Sama obsługa tego peryferala nie jest istotnym elementem w tym komentarzu, więc nie będzie szczegółowo rozpatrywana).
W programie utworzone są następujące zmienne:

Kod: Zaznacz cały

#define CommandBufferSize               64

static LexicalAnalysisInstanceType LexicalAnalysisInstance ;
static uint8_t CommandBuffer [ CommandBufferSize + 1 ] ;
static uint8_t CommandBufferIndex ;
Mają one następujące znaczenie:
  • LexicalAnalysisInstance – instancja analizatora leksykalnego
  • CommandBuffer [ CommandBufferSize + 1 ] – bufor na wczytane poprzez interfejs szeregowy polecenie (stanowi jednowierszowy sektor danych do analizatora),
  • CommandBufferIndex – licznik wczytanych znaków.

Struktura słownika syntaktycznego.

Kod: Zaznacz cały

#define DictionaryWordSize              12

typedef uint8_t SyntaxWordType [ DictionaryWordSize ] ;
typedef enum { DisplaySy                  ,
               SetSy                      ,
               ClearSy                    ,
               AllSy                      ,
               CharSy                     ,
               BitSy                      ,
               BinarySy                   ,
               UnknownWord                } SyntaxSymbolT ;

typedef struct {
                 SyntaxWordType           WordText ;
                 SyntaxSymbolT            WordSymbol ;
               } DictionaryRecT ;

#define DictionarySize                  7

static DictionaryRecT Dictionary [ DictionarySize ] PROGMEM =
  {
/*  0 */ { "DISPLAY    " , DisplaySy } ,
/*  1 */ { "SET        " , SetSy } ,
/*  2 */ { "CLEAR      " , ClearSy } ,
/*  3 */ { "ALL        " , AllSy } ,
/*  4 */ { "CHAR       " , CharSy } ,
/*  5 */ { "BIT        " , BitSy } ,
/*  6 */ { "BIN        " , BinarySy } ,
  } ;
Wymienione elementy mają następujące znaczenie:
  • DictionaryWordSize – liczba znaków każdego wyrazu ze słownika
  • SyntaxWordType [ DictionaryWordSize ] – typ reprezentujący wyraz w słowniku
  • SyntaxSymbolT – typ wyliczeniowy reprezentujący symbole słownika (taki odpowiednik typu LexicSymbolType z modułu analizatora leksykalnego)
  • DictionaryRecT – struktura reprezentująca jeden element słownika.
Sam słownik, jak tablica elementów o typie DictionaryRecT jest powołana jako tablica stała w obrębie pamięci FLASH (jest to element przywiązujący algorytm do architektury Harwardzkiej).
  • DictionarySize – stała określająca liczbę wyrazów w słowniku,
  • Dictionary [ DictionarySize ] – sam słownik, który składa się z par informacji: samego wyrazu i znaczenia przypisanego temu wyrazowi (wyrazy są wpisane wielkimi literami, co w złożeniu z funkcją przeszukującą słownik pozwala na dowolność zapisu w sensie małe lub wielkie litery).
Implementacja funkcji przeszukiwania słownika:

Kod: Zaznacz cały

static SyntaxSymbolT SyntaxDecodeWord ( PtrLexicalAnalysisInstanceType LexicalAnalysisInstance )
{
  uint16_t Loop ;
  uint8_t IntLoop ;
  SyntaxWordType StrToComp ;
  uint8_t Ch1 ;
  uint8_t Ch2 ;
  uint8_t CompareOK ;
  DictionaryRecT DictElement ;
  uint16_t DictionaryArray ;
  /*--------------------------------------------------------------------------*/
  for ( Loop = 0 ; Loop < DictionaryWordSize ; Loop ++ )
  {
    StrToComp [ Loop ] = Cap ( LexicalAnalysisInstance -> InpSpelling [ Loop ] ) ;
  } /* for */ ;
  StrToComp [ DictionaryWordSize - 1 ] = Null ;
  DictionaryArray = ( uint16_t ) & Dictionary ;
  for ( Loop = 0 ; Loop < DictionarySize ; Loop ++ )
  {
    GetPGMBlock ( & DictElement , DictionaryArray , sizeof ( DictionaryRecT ) ) ;
    DictionaryArray += sizeof ( DictionaryRecT ) ;
    CompareOK = TRUE ;
    for ( IntLoop = 0 ; IntLoop < DictionaryWordSize ; IntLoop ++ )
    {
      Ch1 = StrToComp [ IntLoop ] ;
      Ch2 = DictElement . WordText [ IntLoop ] ;
      if ( Ch1 != Ch2 )
      {
        CompareOK = FALSE ;
        break ;
      } /* if */ ;
    } /* for */ ;
    if ( CompareOK )
      return ( DictElement . WordSymbol ) ;
  } /* for */ ;
  return ( UnknownWord ) ;
} /* SyntaxDecodeWord */
Ostatnio wczytany element leksykalny znajduje się w instancji analizatora leksykalnego w polu o nazwie InpSpelling. Zawartość tego pola jest przepisana do zmiennej lokalnej i znormalizowana do wielkich liter (funkcja Cap importowana poprzez #include "stringsmodule.h"). W pętli przepisywany jest do zmiennej lokalnej (funkcja GetPGMBlock importowana poprzez #include "stringsmodule.h") kolejny element tablicy słownika, który stanowi wzorzec do porównania. Porównanie realizowane jest na identyczność. W przypadku zgodności zwracany jest skojarzony z wyrazem symbol syntaktyczny.
Implementacja analizy syntaktycznej i semantycznej oraz ewentualnego wykonania czynności opisanych przez wczytane polecenie.

Kod: Zaznacz cały

static void ExecuteCommand ( void )
{
//
// display set all
// display clear all
// display set bit <numer>
// display clear bit <numer>
// display set bin <liczba>
// display clear bin <liczba>
// display set char "<znak>"
// display clear char "<znak>"
//
  LexicSymbolType LexicSymbol ;
  SyntaxSymbolT SyntaxSymbol ;
  uint8_t SetOperation ;
  uint8_t Operand ;
  uint8_t Tmp ;
  uint8_t AllOperand ;
  /*-------------------------------------------------------------------------*/
  SetOperation = FALSE ;
  AllOperand = FALSE ;
  OpenSectorAnalyser ( & LexicalAnalysisInstance , CommandBuffer , CommandBufferIndex , NIL , NIL ) ;
  LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ErrorCode ) ;
  if ( LexicSymbol == LexicIdentSy )
  {
    SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
    if ( SyntaxSymbol == DisplaySy )
    {
      LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ErrorCode ) ;
      if ( LexicSymbol == LexicIdentSy )
      {
        SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
        switch ( SyntaxSymbol )
        {
          case SetSy            :
            SetOperation = TRUE ;
            break ;
          case ClearSy          :
            SetOperation = FALSE ;
            break ;
          default               :
            AnalError ( ErrorCode , & LexicalAnalysisInstance ) ;
        } /* switch */ ;
        LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ErrorCode ) ;
        if ( LexicSymbol == LexicIdentSy )
        {
          SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
          switch ( SyntaxSymbol )
          {
            case AllSy           :
              AllOperand = TRUE ;
              break ;
            case CharSy          :
              LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicSConstSy , ErrorCode ) ;
              if ( StrLen ( LexicalAnalysisInstance . SInpValue ) != 1 )
              {
                AnalSError ( ErrorCode , LexicalAnalysisInstance . SInpValue , & LexicalAnalysisInstance ) ;
              } /* if */ ;
              Operand = LexicalAnalysisInstance . SInpValue [ 0 ] ;
              break ;
            case BitSy           :
              LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicCConstSy , ErrorCode ) ;
              if ( LexicalAnalysisInstance . CInpValue > 7 )
              {
                AnalLCError ( ErrorCode , LexicalAnalysisInstance . CInpValue , & LexicalAnalysisInstance ) ;
              } /* if */ ;
              Tmp = ( ( uint8_t ) LexicalAnalysisInstance . CInpValue ) & 0x07 ;
              Operand = ( 1 ) << Tmp ;
              break ;
            case BinarySy        :
              LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicCConstSy , ErrorCode ) ;
              if ( LexicalAnalysisInstance . CInpValue > 255 )
              {
                AnalLCError ( ErrorCode , LexicalAnalysisInstance . CInpValue , & LexicalAnalysisInstance ) ;
              } /* if */ ;
              Operand = ( uint8_t ) LexicalAnalysisInstance . CInpValue ;
              break ;
            default              :
              AnalError ( ErrorCode , & LexicalAnalysisInstance ) ;
          } /* switch */ ;
          CheckEndOfLine ( & LexicalAnalysisInstance , ErrorCode ) ;
        } /* if */ ;
      } /* if */ ;
    } /* if ... */
    else
    {
      AnalError ( ErrorCode , & LexicalAnalysisInstance ) ;
    } /* if ... else */ ;
  } /* if */ ;
  if ( ErrorsPresent ( & LexicalAnalysisInstance ) )
  {
    DisplayErrors ( & LexicalAnalysisInstance ) ;
  } /* if ... */
  else
  {
    if ( SetOperation )
    {
      if ( AllOperand )
        LEDData = 0xFF ;
      else
        LEDData = LEDData | Operand ;
    } /* if ... */
    else
    {
      if ( AllOperand )
        LEDData = 0 ;
      else
        LEDData = LEDData & ( ~ Operand ) ;
    } /* if ... else */ ;
    LEDPort = LEDData ;
  } /* if ... else */ ;
  CloseSectorAnalyser ( & LexicalAnalysisInstance ) ;
} /* ExecuteCommand */
Zapis: OpenSectorAnalyser ( & LexicalAnalysisInstance , CommandBuffer , CommandBufferIndex , NIL , NIL ) ; inicjuje instancję analizatora leksykalnego do działania, podłącza do analizatora sektor wczytanych danych (parametr CommandBuffer) wraz z informacją o jego wielkości (CommandBufferIndex). Pierwszy wskaźnik NIL oznacza, że nie jest wymagany raport z analizy (nie wskazuje żadnej metody związanej z „udostępnieniem światu” tekstu raportu). Drugi wskaźnik NIL nie wskazuje na „ekstra obszar” przydatny w implementacji metod używanych w analizie.
Przykładowy zapis: LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ErrorCode ) ; oznacza wczytanie kolejnego elementu leksykalnego z wiersza i zgłoszenie błędu (ErrorCode), jeżeli tym elementem nie był wyraz (element leksykalny reprezentowany przez LexicIdentSy).
Przykładowy zapis: SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ; oznacza „przetłumaczenie” elementu leksykalnego na syntaktyczny (zdekodowanie wyrazu).
Przykładowy zapis: CheckEndOfLine ( & LexicalAnalysisInstance , ErrorCode ) ; oznacza, program będzie się „czepiał” każdego elementu leksykalnego występującego od aktualnej pozycji analizatora do końca wiersza.
W przypadku napotkania jakichkolwiek błędów (leksykalnych, syntaktycznych, semantycznych) zgłaszany jest błąd. Bardzo uproszczona forma sygnalizacji błędów (kod błędu jest stałą #define ErrorCode 100) bez względu na znaczenie błędu. Również samo „udostępnienie światu” informacji dotyczącej błędu (patrz: DisplayErrors) jest bardzo uproszczone.
Implementacja funkcji związanej z „kompletacją polecenia” jest następująca:

Kod: Zaznacz cały

static void ProcessChar ( uint8_t Ch )
{
  /*-------------------------------------------------------------------------*/
  if ( Ch == Bs )
  {
    if ( CommandBufferIndex )
    {
      CommandBufferIndex -- ;
      CommandBuffer [ CommandBufferIndex ] = Null ;
      RedispBuffer ( ) ;
    } /* if */ ;
    return ;
  } /* if */ ;
  if ( Ch == Cr )
  {
    SendNewLine ( ) ;
    SendNewLine ( ) ;
    ExecuteCommand ( ) ;
    CommandBuffer [ 0 ] = Null ;
    CommandBufferIndex = 0 ;
    return ;
  } /* if */ ;
  if ( Ch >= Space )
  {
    if ( CommandBufferIndex < CommandBufferSize )
    {
      CommandBuffer [ CommandBufferIndex ] = Ch ;
      CommandBufferIndex ++ ;
      CommandBuffer [ CommandBufferIndex ] = Null ;
    } /* if */ ;
    RedispBuffer ( ) ;
  } /* if */ ;
} /* ProcessChar */
Wykrycie w strumieniu znaków z interfejsu szeregowego znaku Bs (na klawiaturze Backspace) usuwa z bufora ostatnio wczytany znak. Odebranie znaku Cr (na klawiaturze Enter) uruchamia proces analizy i realizacji wczytanego polecenia.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Analizator leksykalny

Postautor: gaweł » niedziela 25 cze 2017, 14:14

j23 pisze:A tutaj poniżej w linku kilku programistów pracowało nad USS w języku Pascal:
https://4programmers.net/Forum/Delphi_Pascal/119433-Uniwersalna_Struktura_Slownikowa_Pascal?p=425336#id425336

Coś nie chce działać ten link :(

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Analizator leksykalny

Postautor: gaweł » niedziela 25 cze 2017, 18:34

Bazując na przykładzie 1 zostają wprowadzone następujące modyfikacje:

Kod: Zaznacz cały

#define UnexpectedSymbolErrorCode       100
#define ExpectedDisplaySymbolErrorCode  101
#define ExpectedOperatiomErrorCode      102
#define ExpectedOperatorParamErrorCode  103
#define ExpectedStringConstErrorCode    104
#define UnexpectedNumericConstErrorCode 105
#define StringSizeErrorCode             106
#define ConstOutOfRangeErrorCode        107

static uint8_t InvNumbStateErrorTxt [ ] PROGMEM           = "Niepoprawna postac liczby" ;
static uint8_t InvStrStateErrorTxt [ ] PROGMEM            = "Niepoprawna postac zapisu lancucha znakow" ;
static uint8_t UnexpectedSymbolErrorTxt [ ] PROGMEM       = "Nieoczkiwany symbol" ;
static uint8_t ExpectedDisplaySymbolErrorTxt [ ] PROGMEM  = "Oczkiwany wyraz DISPLAY" ;
static uint8_t ExpectedOperatiomErrorTxt [ ] PROGMEM      = "Oczekiwany wyraz SET lub CLEAR" ;
static uint8_t ExpectedOperatorParamErrorTxt [ ] PROGMEM  = "Oczekiwany wyraz ALL lub CHAR lub BIT lub BIN" ;
static uint8_t ExpectedStringConstErrorTxt [ ] PROGMEM    = "Oczkiwana stala lancuchowa" ;
static uint8_t UnexpectedNumericConstErrorTxt [ ] PROGMEM = "Oczekiwana stala liczbowa" ;
static uint8_t StringSizeErrorTxt [ ] PROGMEM             = "Napis musi byc jednoznakowy" ;
static uint8_t ConstOutOfRangeErrorTxt [ ] PROGMEM        = "Wartosc stalej spoza zakresu" ;
Przewidziane jest to do bardziej szczegółowego raportowania błędów analizy leksykalne, syntaktycznej i semantycznej.
Zmianie ulega również funkcja odpowiedzialna za „informowanie świata” o wykrytych błędach.

Kod: Zaznacz cały

static void DisplayErrors ( PtrLexicalAnalysisInstanceType LexicalAnalysisInstance )
{
  uint8_t Loop ;
  /*-------------------------------------------------------------------------*/
  for ( Loop = 0 ; Loop < LexicalAnalysisInstance -> ErrIndex ; Loop ++ )
  {
    switch ( LexicalAnalysisInstance -> ErrCodes [ Loop ] )
    {
      case InvNumbState                    :
        SendSerialFlashTxt ( InvNumbStateErrorTxt ) ;
        break ;
      case InvStrState                     :
        SendSerialFlashTxt ( InvStrStateErrorTxt ) ;
        break ;
      case UnexpectedSymbolErrorCode       :
        SendSerialFlashTxt ( UnexpectedSymbolErrorTxt ) ;
        break ;
      case ExpectedDisplaySymbolErrorCode  :
        SendSerialFlashTxt ( ExpectedDisplaySymbolErrorTxt ) ;
        break ;
      case ExpectedOperatiomErrorCode      :
        SendSerialFlashTxt ( ExpectedOperatiomErrorTxt ) ;
        break ;
      case ExpectedOperatorParamErrorCode  :
        SendSerialFlashTxt ( ExpectedOperatorParamErrorTxt ) ;
        break ;
      case ExpectedStringConstErrorCode    :
        SendSerialFlashTxt ( ExpectedStringConstErrorTxt ) ;
        break ;
      case UnexpectedNumericConstErrorCode :
        SendSerialFlashTxt ( UnexpectedNumericConstErrorTxt ) ;
        break ;
      case StringSizeErrorCode             :
        SendSerialFlashTxt ( StringSizeErrorTxt ) ;
        break ;
      case ConstOutOfRangeErrorCode        :
        SendSerialFlashTxt ( ConstOutOfRangeErrorTxt ) ;
        break ;
    } /* switch */ ;
    SendSerial ( ' ' ) ;
    SendSerial ( '[' ) ;
    SendSerialTxt ( LexicalAnalysisInstance -> ErrSpell [ Loop ] ) ;
    SendSerial ( ']' ) ;
    SendNewLine ( ) ;
  } /* for */ ;
} /* DisplayErrors */
Rozbudowa stałych do bardziej szczegółowego zgłaszania błędów analizy ma kolejne implikacje:
static void ExecuteCommand ( void )
{
//
// display set all
// display clear all
// display set bit <numer>
// display clear bit <numer>
// display set bin <liczba>
// display clear bin <liczba>
// display set char "<znak>"
// display clear char "<znak>"
//
 LexicSymbolType LexicSymbol ;
 SyntaxSymbolT SyntaxSymbol ;
 uint8_t SetOperation ;
 uint8_t Operand ;
 uint8_t Tmp ;
 uint8_t AllOperand ;
 /*-------------------------------------------------------------------------*/
 SetOperation = FALSE ;
 AllOperand = FALSE ;
 OpenSectorAnalyser ( & LexicalAnalysisInstance , CommandBuffer , CommandBufferIndex , NIL , NIL ) ;
 LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ExpectedDisplaySymbolErrorCode ) ;
 if ( LexicSymbol == LexicIdentSy )
 {
  SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
  if ( SyntaxSymbol == DisplaySy )
  {
   LexicSymbol = AcceptSymbol ( & LexicalAnalysisInstance , LexicIdentSy , ExpectedOperatiomErrorCode ) ;
   if ( LexicSymbol == LexicIdentSy )
   {
    SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
    switch ( SyntaxSymbol )
    {
     case SetSy :
      SetOperation = TRUE ;
      break ;
     case ClearSy :
      SetOperation = FALSE ;
      break ;
     default :
      AnalError ( ExpectedOperatiomErrorCode , & LexicalAnalysisInstance ) ;
    } /* switch */ ;
    LexicSymbol=AcceptSymbol(&LexicalAnalysisInstance,LexicIdentSy,ExpectedOperatorParamErrorCode);
    if ( LexicSymbol == LexicIdentSy )
    {
     SyntaxSymbol = SyntaxDecodeWord ( & LexicalAnalysisInstance ) ;
     switch ( SyntaxSymbol )
     {
      case AllSy :
       AllOperand = TRUE ;
       break ;
      case CharSy :
       LexicSymbol=AcceptSymbol(&LexicalAnalysisInstance,LexicSConstSy,ExpectedStringConstErrorCode);
       if ( StrLen ( LexicalAnalysisInstance . SInpValue ) != 1 )
       {
        AnalSError(StringSizeErrorCode,LexicalAnalysisInstance.SInpValue,&LexicalAnalysisInstance);
       } /* if */ ;
       Operand = LexicalAnalysisInstance . SInpValue [ 0 ] ;
       break ;
      case BitSy :
       LexicSymbol=AcceptSymbol(&LexicalAnalysisInstance,LexicCConstSy,UnexpectedNumericConstErrorCode);
       if ( LexicalAnalysisInstance . CInpValue > 7 )
       {
        AnalLCError(ConstOutOfRangeErrorCode,LexicalAnalysisInstance.CInpValue,&LexicalAnalysisInstance);
       } /* if */ ;
       Tmp = ( ( uint8_t ) LexicalAnalysisInstance . CInpValue ) & 0x07 ;
       Operand = ( 1 ) << Tmp ;
       break ;
      case BinarySy :
       LexicSymbol=AcceptSymbol(&LexicalAnalysisInstance,LexicCConstSy,UnexpectedNumericConstErrorCode);
       if ( LexicalAnalysisInstance . CInpValue > 255 )
       {
        AnalLCError(ConstOutOfRangeErrorCode,LexicalAnalysisInstance.CInpValue,&LexicalAnalysisInstance);
       } /* if */ ;
       Operand = ( uint8_t ) LexicalAnalysisInstance . CInpValue ;
       break ;
      default :
       AnalError ( ExpectedOperatorParamErrorCode , & LexicalAnalysisInstance ) ;
     } /* switch */ ;
     CheckEndOfLine ( & LexicalAnalysisInstance ,UnexpectedSymbolErrorCode ) ;
    } /* if */ ;
   } /* if */ ;
  } /* if ... */
  else
  {
   AnalError ( ExpectedDisplaySymbolErrorCode , & LexicalAnalysisInstance ) ;
  } /* if ... else */ ;
  } /* if */ ;
  if ( ErrorsPresent ( & LexicalAnalysisInstance ) )
  {
  DisplayErrors ( & LexicalAnalysisInstance ) ;
  } /* if ... */
  else
  {
  if ( SetOperation )
  {
   if ( AllOperand )
    LEDData = 0xFF ;
   else
    LEDData = LEDData | Operand ;
  } /* if ... */
  else
  {
   if ( AllOperand )
    LEDData = 0 ;
   else
    LEDData = LEDData & ( ~ Operand ) ;
  } /* if ... else */ ;
  LEDPort = LEDData ;
  } /* if ... else */ ;
  CloseSectorAnalyser ( & LexicalAnalysisInstance ) ;
} /* ExecuteCommand */

Efekt na ekranie terminala jest następujący:

Kod: Zaznacz cały

Czesc koles z www.microgeek.eu:
Napisz polecenie


cos?

Oczkiwany wyraz DISPLAY [cos]
display

Oczekiwany wyraz SET lub CLEAR [<EOL>]
display set

Oczekiwany wyraz ALL lub CHAR lub BIT lub BIN [<EOL>]
display set char

Oczkiwana stala lancuchowa [<EOL>]
Napis musi byc jednoznakowy []
display set char '*

Niepoprawna postac zapisu lancucha znakow ['*<EOL>]
display set char "**"

Napis musi byc jednoznakowy [**]
display set char 'X'

display set bit 111

Wartosc stalej spoza zakresu [111]
display set bin 111

display set bin 333

Wartosc stalej spoza zakresu [333]
display set all i cos innego

Nieoczkiwany symbol [i]
Nieoczkiwany symbol [cos]
Nieoczkiwany symbol [innego]
display clear all



Załącznik: projekt w AVR STUDIO:
syntax2.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
j23
Expert
Expert
Posty: 506
Rejestracja: czwartek 08 paź 2015, 18:40

Re: Analizator leksykalny

Postautor: j23 » niedziela 25 cze 2017, 18:39

gaweł pisze:
j23 pisze:A tutaj poniżej w linku kilku programistów pracowało nad USS w języku Pascal:
https://4programmers.net/Forum/Delphi_Pascal/119433-Uniwersalna_Struktura_Slownikowa_Pascal?p=425336#id425336

Coś nie chce działać ten link :(


A może tak... Tu link do Google i dalej pierwszy link z góry.

Pozdrawiam! Jarek
Internet łączy ludzi, którzy dzielą się swoimi zainteresowaniami, pomysłami i potrzebami, bez względu na geograficzne (przeciwności).
BOB TAYLOR, PARC

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Analizator leksykalny

Postautor: gaweł » niedziela 25 cze 2017, 18:58

j23 pisze:A może tak... Tu link do Google i dalej pierwszy link z góry.

Ten sam efekt:
scr.PNG


Ale poradzę sobie, poszukam inaczej.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
j23
Expert
Expert
Posty: 506
Rejestracja: czwartek 08 paź 2015, 18:40

Re: Analizator leksykalny

Postautor: j23 » niedziela 25 cze 2017, 22:19

Kolego Gaweł, musisz dodać wyjątek w zaporze systemowej Windows i/lub dodać certyfikat autentyczności dla tej witryny.
Pozdrawiam! Jarek
Internet łączy ludzi, którzy dzielą się swoimi zainteresowaniami, pomysłami i potrzebami, bez względu na geograficzne (przeciwności).
BOB TAYLOR, PARC


Wróć do „Inne mikroklocki, również peryferyjne”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 2 gości