Camp4

Camlp4 to system oprogramowania do pisania rozszerzalnych parserów dla języków programowania. Zapewnia zestaw OCaml , które są używane do definiowania gramatyk, a także ładowalne rozszerzenia składni takich gramatyk. Camlp4 oznacza Caml Preprocessor i Pretty-Printer , a jednym z jego najważniejszych zastosowań było definiowanie specyficznych dla domeny rozszerzeń składni OCaml .

Camlp4 był częścią oficjalnej dystrybucji OCaml, która jest rozwijana w INRIA . Jego oryginalnym autorem jest Daniel de Rauglaudre. Wersja OCaml 3.10.0, wydana w maju 2007 roku, wprowadziła znacznie zmodyfikowaną i niekompatybilną wstecz wersję Camlp4. De Rauglaudre utrzymuje oddzielną, wstecznie kompatybilną wersję, której nazwę zmieniono na Camlp5. Wszystkie poniższe przykłady dotyczą Camlp5 lub poprzedniej wersji Camlp4 (wersje 3.09 i wcześniejsze).

Wersja 4.08, wydana latem 2019 roku, była ostatnią oficjalną wersją tej biblioteki. Obecnie jest przestarzały; zamiast tego zaleca się korzystanie z bibliotek PPX (PreProcessor eXtensions).

Składnia konkretna i abstrakcyjna

Preprocesor Camlp4 działa poprzez ładowanie kolekcji skompilowanych modułów, które definiują parser oraz ładną drukarkę : parser konwertuje program wejściowy na wewnętrzną reprezentację. Ta wewnętrzna reprezentacja stanowi abstrakcyjne drzewo składniowe (AST). Może być wyprowadzony w postaci binarnej, np. może być przekazany bezpośrednio do jednego z kompilatorów OCaml lub może zostać przekonwertowany z powrotem do programu w postaci zwykłego tekstu. Pojęcie składni konkretnej odnosi się do formatu, w jakim reprezentowana jest składnia abstrakcyjna .

wyrażenie OCaml (1 + 2) można również zapisać ((+) 1 2) lub (((+) 1) 2). Różnica jest tylko na poziomie konkretnej składni, ponieważ te trzy wersje są równoważnymi reprezentacjami tego samego abstrakcyjnego drzewa składniowego. Jak pokazuje definicja zmienionej składni dla OCaml, ten sam język programowania może wykorzystywać różne konkretne składnie. Wszystkie zbiegałyby się w abstrakcyjne drzewo składniowe w unikalnym formacie, który może obsłużyć kompilator.

Abstrakcyjne drzewo składniowe znajduje się w centrum rozszerzeń składni, które w rzeczywistości są programami OCaml. Chociaż definicja gramatyki musi być wykonana w OCaml, parser, który jest definiowany lub rozszerzany, niekoniecznie jest powiązany z OCamlem, w którym to przypadku manipulowane drzewo składni nie jest drzewem OCaml. Dostępnych jest kilka bibliotek, które ułatwiają specyficzną manipulację drzewami składni OCaml.

Obszary zastosowania

Języki specyficzne dla domeny są głównym zastosowaniem Camlp4. Ponieważ OCaml jest językiem wieloparadygmatowym, z interaktywnym najwyższym poziomem i natywnym kompilatorem kodu, może być używany jako backend dla dowolnego oryginalnego języka. Jedyne, co programista musi zrobić, to napisać gramatykę Camlp4, która konwertuje dany język specyficzny dla domeny na zwykły program OCaml. Można również użyć innych języków docelowych, takich jak C .

Jeśli językiem docelowym jest OCaml, można zdefiniować proste dodatki składniowe lub cukier składniowy , aby zapewnić ekspresyjność, która nie jest łatwa do osiągnięcia przy użyciu standardowych funkcji języka OCaml. Rozszerzenie składni jest definiowane przez skompilowany moduł OCaml, który jest przekazywany do pliku wykonywalnego camlp4o wraz z programem do przetworzenia.

Camlp4 zawiera język specyficzny dla domeny, ponieważ zapewnia rozszerzenia składni, które ułatwiają tworzenie rozszerzeń składni. Rozszerzenia te pozwalają na zwięzłą definicję gramatyk ( EXTEND ) i cudzysłowów, takich jak <:expr< 1 + 1 >>, czyli dekonstrukcja i konstruowanie abstrakcyjnych drzew składniowych w składni konkretnej.

Przykład

Poniższy przykład definiuje rozszerzenie składni OCaml. Zapewnia nowe słowo kluczowe , memo , które może być użyte jako zamiennik funkcji i zapewnia automatyczne zapamiętywanie funkcji z dopasowaniem do wzorca . Zapamiętywanie polega na przechowywaniu wyników poprzednich obliczeń w tabeli, tak aby rzeczywiste obliczenie funkcji dla każdego możliwego argumentu wystąpiło co najwyżej raz.

To jest pa_memo.ml, plik definiujący rozszerzenie składni:

  
      0 
          


   

     
              
           
           
           
       
           
        
            
            
                         
                      
                       
       
  

   
                   
           
          
  
 niech  unikalny  =  niech  n  =  ref  w  zabawie  ()  ->  incr  n  ;  "__pa_memo"  ^  string_of_int  !  n  ROZSZERZ  GLOBALNIE  :  Pcaml  .  wyrażenie  ;  Pcaml  .  wyr  :  POZIOM  "wyr1"  [  [  "notatka"  ;  OPCJA  "|"  ;  pel  =  LISTA 1  mecz_przypadek  SEP  "|"  ->  niech  tbl  =  unikalny  ()  w  niech  x  =  unikalny  ()  w  niech  wynik  =  unikalny  ()  w  <:  wyrażenie  <  niech  $  lid  :  tbl  $  =  Hashtbl  .  utwórz  100  w  fun  $  lid  :  x  $  ->  wypróbuj  Hashtbl  .  znajdź  $  lid  :  tbl  $  $  lid  :  x  $  z  [  Not_found  ->  niech  $  lid  :  wynik  $  =  dopasuj  $  lid  :  x  $  z  [  $  list  :  pel  $  ]  w  do  {  Hashtbl  .  zamień  $  pokrywa  :  tbl  $  $  pokrywa  :  x  $  $  pokrywa  :  wynik  $;  $  pokrywa  :  wynik  $  }  ]  >>  ]  ];  przypadek_dopasowania  :  [  [  p  =  Pcaml  .  patt  ;  w  =  OPT  [  "kiedy"  ;  e  =  Pcaml  .  wyrażenie  ->  e  ];  "->"  ;  e  =  Pcaml  .  wyrażenie  ->  (  p  ,  w  ,  e  )  ]  ];  KONIEC 

Przykład programu korzystającego z tego rozszerzenia składni:

    0 


    
    0  
       0  
       
            
      

   
       
      
   
       

  
       niech  licznik  =  ref  (* globalny licznik mnożeń *)  (* silnia z zapamiętywaniem *)  niech  rec  fac  =  memo  ->  1  |  n  gdy  n  >  ->  (  incr  licznik  ;  n  *  fac  (  n  -  1  ))  |  _  ->  niepoprawny_arg  "fac"  niech  działa  n  =  niech  wynik  =  fac  n  in  niech  liczy  =  !  licznik  w  Printf  .  printf  "%i! = %i liczba mnożeń do tej pory = %i  \n  "  n  liczba  wyników  niech  _  =  Lista  .  iter  uruchom  [  5  ;  4  ;  6  ] 

Dane wyjściowe programu są następujące i pokazują, że funkcja fac (silnia) oblicza tylko iloczyny, które nie zostały wcześniej obliczone:

5! = 120 liczba dotychczasowych mnożeń = 5 4! = 24 liczba dotychczasowych mnożeń = 5 6! = 720 liczba mnożeń do tej pory = 6
  1. Bibliografia _ _ GitHub . Źródło 2020-02-04 .
  2. ^ Dimino, Jérémie (2019-08-07). „Koniec Camlp4” . OCaml . Zarchiwizowane od oryginału w dniu 2020-02-04 . Źródło 2020-02-04 .
  3. Bibliografia _ _ ocamllabs.io . Źródło 2020-02-04 .
  4. Bibliografia _ „Przewodnik po rozszerzeniach preprocesora” . OCamlwersum . Zarchiwizowane od oryginału w dniu 2020-02-05 . Źródło 2020-02-05 .
  5. Bibliografia _ „Konwersja bazy kodu z camlp4 na ppx” . Blog techniczny Jane Street . Zarchiwizowane od oryginału w dniu 2020-02-04 . Źródło 2020-02-04 .

Linki zewnętrzne