هل يمكنني استخدام anxer/parser تم إنشاؤه ANTLR لتحليل ملف PDDL وإرجاع البيانات إلى برنامج Java؟

StackOverflow https://stackoverflow.com/questions/3818442

  •  26-09-2019
  •  | 
  •  

سؤال

أنا جديد على Antlr ، لكنني استخدمت Flex/Bison من قبل. أريد أن أعرف ما إذا كان ما أريد القيام به باستخدام Antlr ممكن.

أرغب في تحليل ملف PDDL باستخدام Antlr وإنشاء تمثيلي الخاص لمحتويات ملف PDDL في فئة Java التي كتبتها كملف PDDL (في الإجراءات الخاصة بالقواعد؟). بعد الانتهاء من تحليل الملف ، أريد إرجاع تمثيل كائن محتويات الملف إلى برنامج Java لتشغيل عمليات أخرى عليها.

لذلك ، أريد أن أؤدي إلى محلل PDDL الذي تم إنتاجه على Antler على ملف PDDL من داخل برنامج Java وأعيد كائنًا يصف ملف PDDL إلى برنامج Java الرئيسي.

هل هذا ممكن؟ لقد حاولت النظر إلى الوثائق ، لكنني لم أجد إجابة جيدة.

شكرا جزيلا.

هل كانت مفيدة؟

المحلول

لذلك ، أريد أن أؤدي إلى محلل PDDL الذي تم إنتاجه على Antler على ملف PDDL من داخل برنامج Java وأعيد كائنًا يصف ملف PDDL إلى برنامج Java الرئيسي.

هل هذا ممكن؟

بالتأكيد.

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

دعنا نقول أن لغة PDDL هي مجرد لغة سهلة: إنها سلسلة من الأرقام أو أكثر إما في سداسي عشري (0x12FD) ، أوكتال (0745) أو تدوين عشري (12345) مفصولة بمساحات بيضاء. يمكن وصف هذه اللغة في ملف قواعد AntlR التالية المسمى PDDL.g:

grammar PDDL;

parse
  :  number+ EOF
  ;

number
  :  Hex
  |  Dec
  |  Oct
  ;

Hex
  :  '0' ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+
  ;

Dec
  :  '0'
  |  '1'..'9' ('0'..'9')*
  ;

Oct
  :  '0' '0'..'7'+
  ;

Space
  :  (' ' | '\t' | '\r' | '\n'){$channel=HIDDEN;}
  ;

في هذه القواعد النحوية ، فإن القواعد (تحليل ، العدد ، السداسي ، ... هي القواعد) التي تبدأ برأس المال هي قسائم lexer. والآخرون هم محللون.

من هذه القواعد النحوية ، يمكنك إنشاء Lexer و Larser مثل هذا:

java -cp antlr-3.2.jar org.antlr.Tool PDDL.g

الذي ينتج (على الأقل) الملفات PDDLParser.java و PDDLLexer.java.

الآن قم بإنشاء فئة اختبار صغيرة يمكنك من خلالها استخدام فئات Lexer و Larser هذه:

import org.antlr.runtime.*;
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        File source = new File("source.txt");
        ANTLRInputStream in = new ANTLRInputStream(new FileInputStream(source));
        PDDLLexer lexer = new PDDLLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        PDDLParser parser = new PDDLParser(tokens);
        parser.parse();
    }
}

حيث محتويات source.txt قد يبدو الملف هكذا:

0xcAfE 0234
66678 0X12 0777

الآن تجميع الكل .java الملفات:

javac -cp antlr-3.2.jar *.java

وتشغيل الفصل الرئيسي:

// Windows
java -cp .;antlr-3.2.jar Main

// *nix/MacOS
java -cp .:antlr-3.2.jar Main

إذا سارت الأمور على ما يرام ، لا يتم طباعة أي شيء إلى وحدة التحكم.

أنت تقول الآن أنك تريد السماح للمحلل بإعادة كائنات معينة بناءً على محتويات ملف المصدر الخاص بك. دعنا نقول أننا نريد أن تعيد قواعدنا List<Integer>. يمكن القيام بذلك عن طريق تضمين "الإجراءات" في قواعد القواعد مثل هذا:

grammar PDDL;

parse returns [List<Integer> list]
@init{$list = new ArrayList<Integer>();}
  :  (number {$list.add($number.value);})+ EOF
  ;

number returns [Integer value]
  :  Hex {$value = Integer.parseInt($Hex.text.substring(2), 16);}
  |  Dec {$value = Integer.parseInt($Dec.text);}
  |  Oct {$value = Integer.parseInt($Oct.text, 8);}
  ;

Hex
  :  '0' ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+
  ;

Dec
  :  '0'
  |  '1'..'9' ('0'..'9')*
  ;

Oct
  :  '0' '0'..'7'+
  ;

Space
  :  (' ' | '\t' | '\r' | '\n'){$channel=HIDDEN;}
  ;

كما ترون ، يمكنك السماح للقواعد بإرجاع الكائنات (returns [Type t]) ويمكن تضمين رمز Java العادي إذا لفها في { و }. ال @init جزء في parse يتم وضع القاعدة في بداية parse الطريقة في PDDLParser.java ملف.

اختبر المحلل الجديد مع هذه الفئة:

import org.antlr.runtime.*;
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        File source = new File("source.txt");
        ANTLRInputStream in = new ANTLRInputStream(new FileInputStream(source));
        PDDLLexer lexer = new PDDLLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        PDDLParser parser = new PDDLParser(tokens);
        List<Integer> numbers = parser.parse();
        System.out.println("After parsing :: "+numbers);
    }
}

وسترى ما يلي طبعت إلى وحدة التحكم:

After parsing :: [51966, 156, 66678, 18, 511]

نصائح أخرى

من المؤكد أن هذا ممكن ، نظرًا لأن ANTLR مصمم لإنشاء محلات يتم استدعاءها بعد ذلك كجزء من نظام أكبر (على سبيل المثال ، برنامج التحويل البرمجي أو محلل رمز ثابت).

ابدأ بـ Terence Parr's مرجع antlr النهائي: البناء لغات خاصة بالمجال. إنه مؤلف Antlr ، وأيضًا مدرسًا غير عادي وخالي من المصطلحات حول معالجة اللغة.

مارتن فاولر اللغات الخاصة بالمجال يستخدم AntlR في الكثير من أمثلةها. على سبيل المثال في الصفحة 200 ، يعرض مثالًا بسيطًا "Hello World" حيث يقوم برنامج Java باستدعاء Antlr لتحليل ملف للأشخاص لتحية ، وأثناء القيام به ينبعث من التحيات. إليك المكان الذي يتم فيه العمل (صفحة 206):

class GreetingsLoader. ..
  public void run() {
    try {
      GreetingsLexer lexer = new GreetingsLexer(new ANTLRReaderStream(input));
      GreetingsParser parser = new GreetingsParser(new CommonTokenStream(lexer));
      parser.helper = this;
      parser.script() ;
      if (hasErrors() ) throw new RuntimeException("it all went pear-shaped\n" +
 errorReport() ) ;
    } catch (IOException e) {
      throw new RuntimeException( e) ;
    } catch (RecognitionException e) {
      throw new RuntimeException( e) ;
    }
  }

كتاب جيد ثالث هو كتاب تيرينس الجديد على DSLS أنماط تنفيذ اللغة. يصف الطرق المختلفة لاستخدام AntlR ، كما هو الحال في كتابة مولد شجرة بناء جملة مجردة لوضعه في برنامج التحويل البرمجي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top