Camlp4

Camlp4 هو نظام برمجي لكتابة محللات قابلة للتوسيع للغات البرمجة. يوفر مجموعة من مكتبات OCaml تُستخدم لتعريف القواعد النحوية، بالإضافة إلى امتدادات بناء الجملة القابلة للتحميل لهذه القواعد. يرمز Camlp4 إلى معالج Caml المسبق وطابعة التنسيق ، وكان من أهم تطبيقاته تعريف امتدادات خاصة بمجالات محددة لبناء جملة OCaml .

كانت لغة Camlp4 جزءًا من توزيعة OCaml الرسمية التي طُوّرت في معهد INRIA . مؤلفها الأصلي هو دانيال دي روغلاودر. أصدرت OCaml الإصدار 3.10.0 في مايو 2007، والذي تضمن نسخة مُعدّلة بشكل كبير من Camlp4 وغير متوافقة مع الإصدارات السابقة . يحتفظ دي روغلاودر بنسخة منفصلة متوافقة مع الإصدارات السابقة، أُعيد تسميتها إلى Camlp5. جميع الأمثلة أدناه خاصة بلغة Camlp5 أو الإصدار السابق من Camlp4 (الإصدار 3.09 وما قبله).

كان الإصدار 4.08، الذي صدر في صيف 2019، [ 1 ] آخر إصدار رسمي لهذه المكتبة. وهو الآن مُهمل؛ [ 2 ] ويُنصح بدلاً منه باستخدام مكتبات PPX (امتدادات المعالج المسبق) [ 3 ] [ 4 ] . [ 5 ]

بناء الجملة الملموس والمجرد

يعمل معالج Camlp4 المسبق عن طريق تحميل مجموعة من الوحدات المُجمَّعة التي تُعرِّف مُحلِّلًا نحويًا ومُنسِّقًا للعرض : يُحوِّل المُحلِّل النحوي برنامج الإدخال إلى تمثيل داخلي. يُشكِّل هذا التمثيل الداخلي شجرة بناء الجملة المجردة (AST). يُمكن إخراجها بصيغة ثنائية، على سبيل المثال، يُمكن تمريرها مباشرةً إلى أحد مُجمِّعات OCaml ، أو يُمكن تحويلها مرة أخرى إلى برنامج نصي واضح. يُشير مفهوم بناء الجملة الملموس إلى الصيغة التي يُمثَّل بها بناء الجملة المجرد .

على سبيل المثال، يمكن كتابة تعبير OCaml (1 + 2) أيضًا على النحو ((+) 1 2) أو (((+) 1) 2). يكمن الاختلاف فقط على مستوى الصيغة الملموسة، لأن هذه الصيغ الثلاث تمثل تمثيلات متكافئة لنفس شجرة الصيغة المجردة. وكما يتضح من تعريف الصيغة المعدلة لـ OCaml، يمكن للغة البرمجة نفسها استخدام صيغ ملموسة مختلفة. ستتقارب جميعها إلى شجرة صيغة مجردة بتنسيق فريد يمكن للمترجم التعامل معه.

The abstract syntax tree is at the center of the syntax extensions, which are in fact OCaml programs. Although the definition of grammars must be done in OCaml, the parser that is being defined or extended is not necessarily related to OCaml, in which case the syntax tree that is being manipulated is not the one of OCaml. Several libraries are provided which facilitate the specific manipulation of OCaml syntax trees.

Fields of application

Domain-specific languages are a major application of Camlp4. Since OCaml is a multi-paradigm language, with an interactive toplevel and a native code compiler, it can be used as a backend for any kind of original language. The only thing that the developer has to do is write a Camlp4 grammar which converts the domain-specific language in question into a regular OCaml program. Other target languages can also be used, such as C.

If the target language is OCaml, simple syntax add-ons or syntactic sugar can be defined, in order to provide an expressivity which is not easy to achieve using the standard features of the OCaml language. A syntax extension is defined by a compiled OCaml module, which is passed to the camlp4o executable along with the program to process.

Camlp4 includes a domain-specific language as it provides syntax extensions which ease the development of syntax extensions. These extensions allow a compact definition of grammars (EXTEND statements) and quotations such as <:expr< 1 + 1 >>, i.e. deconstructing and constructing abstract syntax trees in concrete syntax.

Example

The following example defines a syntax extension of OCaml. It provides a new keyword, memo, which can be used as a replacement for function and provides automatic memoization of functions with pattern matching. Memoization consists in storing the results of previous computations in a table so that the actual computation of the function for each possible argument occurs at most once.

This is pa_memo.ml, the file which defines the syntax extension:

letunique=letn=ref0infun()->incrn;"__pa_memo"^string_of_int!nEXTENDGLOBAL:Pcaml.expr;Pcaml.expr : LEVEL " expr1 " [ [ "memo" ; OPT "|" ; pel = LIST1 match_case SEP "|" - > let tbl = unique ( ) in let x = unique ( ) in let result = unique () in < : expr < let $ lid : tbl $ = Hashtbl.create100 in fun $ lid : x $ ​​- > try Hashtbl.find $ lid : tbl $ $ lid : x $ ​​with [ Not_found -> let $ lid : result $ = match $ lid : x $ ​​with [ $ list : pel $ ] in do { Hashtbl.replace $ lid : tbl $ $ lid : x $ ​​$ lid : result $ ; $ lid : result $ } ] >> ] ] ;match_case : [ [ p = Pcaml . patt ; w = OPT [ "when" ; e = Pcaml . expr -> e ]; "->" ; e = Pcaml . expr -> ( p , w , e ) ] ]; END

مثال على برنامج يستخدم هذا الامتداد النحوي:

let counter = ref 0 (* عداد عام لعمليات الضرب *)(* حساب المضروب مع التخزين المؤقت *) let rec fac = memo 0 -> 1 | n when n > 0 -> ( incr counter ; n * fac ( n - 1 )) | _ -> invalid_arg "fac"let run n = let result = fac n in let count = ! counter in Printf . printf "%i! = %i عدد عمليات الضرب حتى الآن = %i \n " n result countlet _ = List . iter run [ 5 ; 4 ; 6 ]

يُظهر ناتج البرنامج ما يلي، موضحًا أن دالة fac (المضروب) لا تحسب إلا المنتجات التي لم يتم حسابها مسبقًا:

5! = 120 عدد عمليات الضرب حتى الآن = 5 4! = 24 عدد عمليات الضرب حتى الآن = 5 6! = 720 عدد عمليات الضرب حتى الآن = 6

مراجع

  1. "ocaml/camlp4" . GitHub . تم الاسترجاع في 2020-02-04 .
  2. ديمينو، جيريمي (2019-08-07). "نهاية Camlp4" . OCaml . مؤرشف من الأصل في 2020-02-04 . تم الاسترجاع في 2020-02-04 .
  3. "PPX" . ocamllabs.io . تم ​​الاطلاع عليه بتاريخ 2020-02-04 .
  4. ميتزجر، بيري. "دليل ملحقات المعالج المسبق" . OCamlverse . مؤرشف من الأصل بتاريخ 2020-02-05 . تم الاسترجاع بتاريخ 2020-02-05 .
  5. ديمينو، جيريمي. "تحويل قاعدة بيانات برمجية من camlp4 إلى ppx" . مدونة جين ستريت التقنية . مؤرشف من الأصل بتاريخ 4 فبراير 2020. تم الاطلاع عليه بتاريخ 4 فبراير 2020 .