এএনটিএলআরে একটি 'সিনমেটিক প্রিডিকেট' কী?


103

একটি কি শব্দার্থিক সম্পৃক্ত ANTLR মধ্যে?


3
মনে রাখবেন যেহেতু আমি যাহার অর্থার্থক ভবিষ্যদ্বাণীটি কী তা জানতে চাইবার জন্য পোস্ট করার জন্য একটি শালীন অনলাইন সংস্থান খুঁজে পাইনি, তাই আমি নিজেই এখানে প্রশ্নটি পোস্ট করার সিদ্ধান্ত নিয়েছি (যার বিষয়ে আমি নিজেই উত্তর দেব) answer
বার্ট কায়ার্স

1
এটি করার জন্য ধন্যবাদ; আমি সর্বদা এটি পছন্দ করি যখন লোকেরা তাদের নিজস্ব প্রশ্নের উত্তর দেয়, বিশেষত যদি তারা এইভাবে উত্তরটির জন্য বিশেষত প্রশ্নটি জিজ্ঞাসা করে।
ড্যানিয়েল এইচ

1
বই পড়ুন। সংজ্ঞাসংক্রান্ত এএনটিএলআর 4 এর সিএফ 11 রেফারেন্সটি সিনমেটিক পূর্বাভাসের উপর। বই নেই? এটা নাও! প্রতি ডলার মূল্য।
james.garriss

উত্তর:


169

এএনটিএলআর 4

এএনটিএলআর 4 এ পূর্বাভাসের জন্য, এই স্ট্যাকের ওভারফ্লো প্রশ্নোত্তর ও চেক আউট :


এএনটিএলআর 3

প্লেইন কোড ব্যবহার করে ব্যাকরণ ক্রিয়াকলাপগুলির উপর অতিরিক্ত (শব্দার্থবিজ্ঞান) বিধি প্রয়োগ করার একটি অর্থ হল সিনেমিক প্রিডিকেট

3 ধরণের সিমেটিক পূর্বাভাস রয়েছে:

  • বৈধতা দানার্থক ভবিষ্যদ্বাণী;
  • গেটেড সিমেটিক ভবিষ্যদ্বাণী;
  • বিস্ময়কর শব্দার্থক ভবিষ্যদ্বাণী।

ব্যাকরণ উদাহরণ

ধরা যাক যে কোনও সাদা স্পেস উপেক্ষা করে আপনার কাছে কমা দ্বারা পৃথকীকৃত সংখ্যার সমন্বিত পাঠ্যের একটি ব্লক রয়েছে। আপনি সংখ্যাটি সর্বাধিক 3 অঙ্ক "দীর্ঘ" (সর্বাধিক 999) হয় তা নিশ্চিত করে এই ইনপুটটি বিশ্লেষণ করতে চান। নিম্নলিখিত ব্যাকরণ ( Numbers.g) এ জাতীয় কাজ করবে:

grammar Numbers;

// entry point of this parser: it parses an input string consisting of at least 
// one number, optionally followed by zero or more comma's and numbers
parse
  :  number (',' number)* EOF
  ;

// matches a number that is between 1 and 3 digits long
number
  :  Digit Digit Digit
  |  Digit Digit
  |  Digit
  ;

// matches a single digit
Digit
  :  '0'..'9'
  ;

// ignore spaces
WhiteSpace
  :  (' ' | '\t' | '\r' | '\n') {skip();}
  ;

পরীক্ষামূলক

ব্যাকরণটি নিম্নলিখিত শ্রেণীর সাথে পরীক্ষা করা যেতে পারে:

import org.antlr.runtime.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("123, 456, 7   , 89");
        NumbersLexer lexer = new NumbersLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        NumbersParser parser = new NumbersParser(tokens);
        parser.parse();
    }
}

লেক্সার এবং পার্সার জেনারেট করে, সমস্ত .javaফাইল সংকলন করে এবং Mainক্লাস চালিয়ে পরীক্ষা করুন :

java -cp antlr-3.2.jar org.antlr.Tool Numbers.g
javac -cp antlr-3.2.jar *। java
java -cp।: antlr-3.2.jar Main

এটি করার সময়, কনসোলে কিছুই মুদ্রিত হয় না, যা ইঙ্গিত দেয় যে কিছুই ভুল হয়নি। পরিবর্তনের চেষ্টা করুন:

ANTLRStringStream in = new ANTLRStringStream("123, 456, 7   , 89");

মধ্যে:

ANTLRStringStream in = new ANTLRStringStream("123, 456, 7777   , 89");

এবং আবার পরীক্ষা করুন: আপনি স্ট্রিংয়ের ঠিক পরে কনসোলে একটি ত্রুটি উপস্থিত হতে দেখবেন 777


অর্থপূর্ণ ভবিষ্যদ্বাণী

এটি আমাদের অর্থোত্তর পূর্বাভাসে নিয়ে আসে। ধরা যাক আপনি 1 এবং 10 অঙ্কের মধ্যে দীর্ঘ সংখ্যার পার্স করতে চান। একটি নিয়ম যেমন:

number
  :  Digit Digit Digit Digit Digit Digit Digit Digit Digit Digit
  |  Digit Digit Digit Digit Digit Digit Digit Digit Digit
     /* ... */
  |  Digit Digit Digit
  |  Digit Digit
  |  Digit
  ;

জটিল হয়ে উঠবে। শব্দার্থবিজ্ঞান পূর্বাভাসগুলি এই ধরণের নিয়মকে সহজতর করতে সহায়তা করতে পারে।


1. অর্থপূর্ণ ভবিষ্যদ্বাণীগুলি বৈধকরণ

একটি বৈধতাযুক্ত সিনেমিক প্রিডিকেট একটি প্রশ্ন চিহ্নের পরে কোডের ব্লক ছাড়া আর কিছুই নয়:

RULE { /* a boolean expression in here */ }?

বৈধকরণের অর্থপূর্ণ সিন্ডিকেট ব্যবহার করে উপরের সমস্যাটি সমাধান করার জন্য , numberব্যাকরণের নিয়মটি এতে পরিবর্তন করুন :

number
@init { int N = 0; }
  :  (Digit { N++; } )+ { N <= 10 }?
  ;

অংশগুলি { int N = 0; }এবং { N++; }সরল জাভা বিবৃতি যা পার্সার যখন numberনিয়মে "প্রবেশ করে" প্রথমে শুরু হয় । আসল শিকারী হ'ল { N <= 10 }?:, FailedPredicateException যখনই সংখ্যাটি 10 ​​অঙ্কের বেশি লম্বা হয় তখন পার্সারটিকে ফেলে দেয় ।

নিম্নলিখিতটি ব্যবহার করে এটি পরীক্ষা করুন ANTLRStringStream:

// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890"); 

যা কোনও ব্যতিক্রম ঘটায় না, যখন নিম্নলিখিতটি ব্যতিক্রম করে:

// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");

২. গেটেড সিমেন্টিক প্রেডিকেটস

একটি গেটেড সিনমেটিক প্রিডিকেট একটি বৈধকরণের অর্থপূর্ণ সিন্ডিকেটের অনুরূপ , কেবল গেটেড সংস্করণটি একটি এর পরিবর্তে একটি বাক্য গঠন ত্রুটি তৈরি করে FailedPredicateException

একটি উত্সাহী অর্থপূর্ণ সিন্ডিকেট এর বাক্য গঠনটি হ'ল:

{ /* a boolean expression in here */ }?=> RULE

পরিবর্তে উপরের সমস্যার সমাধান করার জন্য গেটেড পূর্বাভাসগুলি ব্যবহার করে 10 টি সংখ্যা পর্যন্ত দীর্ঘ সংখ্যার সাথে মিল রাখতে আপনি লিখবেন:

number
@init { int N = 1; }
  :  ( { N <= 10 }?=> Digit { N++; } )+
  ;

উভয়ের সাথে এটি আবার পরীক্ষা করুন:

// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890"); 

এবং:

// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");

এবং আপনি দেখতে পাবেন শেষটি একটি ত্রুটি ফেলবে।


৩. অর্থপূর্ণ ভবিষ্যদ্বাণীগুলি অসম্পূর্ণ করা

চূড়ান্ত প্রকারের প্র্যাটিকেট হ'ল একটি বিশৃঙ্খলাবদ্ধ সিনেটিক প্রেডিকেট , যা কিছুটা বৈধতাপ্রাপ্ত প্রাকটিকেট ( {boolean-expression}?) এর মতো দেখায় , তবে এটি আরও উত্সাহযুক্ত সিনমেটিক প্রাকটিকের মতো কাজ করে (বুলিয়ান এক্সপ্রেশনটি মূল্যায়ন করলে কোনও ব্যতিক্রম ছোঁড়া হয় না false)। আপনি কোনও নিয়মের শুরুতে এটি কোনও নিয়মের কিছু সম্পত্তি যাচাই করতে ব্যবহার করতে পারেন এবং পার্সারের সাথে ম্যাচটি নিয়মকে বলে কিনা তা করতে দিন।

আসুন আমরা উদাহরণস্বরূপ ব্যাকরণ Numberটোকেন তৈরি করে (পার্সার নিয়মের পরিবর্তে একটি লেজার নিয়ম) যা 0..999 এর পরিসরে সংখ্যাগুলির সাথে মেলে। এখন পার্সারে, আপনি কম এবং হাইট সংখ্যার (নিম্ন: 0..500, উচ্চ: 501..999) মধ্যে পার্থক্য তৈরি করতে চান। এটি একটি হতাশামূলক অর্থপূর্ণ সিন্ডিকেট ব্যবহার করে করা যেতে পারে যেখানে আপনি স্ট্রিমের পরবর্তী টোকেনটি পরীক্ষা করেন ( input.LT(1)) এটি কম বা উচ্চতর কিনা তা পরীক্ষা করতে।

একটি ডেমো:

grammar Numbers;

parse
  :  atom (',' atom)* EOF
  ;

atom
  :  low  {System.out.println("low  = " + $low.text);}
  |  high {System.out.println("high = " + $high.text);}
  ;

low
  :  {Integer.valueOf(input.LT(1).getText()) <= 500}? Number
  ;

high
  :  Number
  ;

Number
  :  Digit Digit Digit
  |  Digit Digit
  |  Digit
  ;

fragment Digit
  :  '0'..'9'
  ;

WhiteSpace
  :  (' ' | '\t' | '\r' | '\n') {skip();}
  ;

আপনি যদি এখন স্ট্রিংটিকে বিশ্লেষণ করেন "123, 999, 456, 700, 89, 0"তবে নীচের আউটপুটটি দেখতে পাবেন:

low  = 123
high = 999
low  = 456
high = 700
low  = 89
low  = 0

12
ম্যান আপনার সত্যই
এএনটিএলআর

5
@ বার্ট কায়ারস: দয়া করে এএনটিএলআর একটি বই লিখুন
সন্তোষ সিংহ

2
ANTLR V4 জন্য, input.LT(1)হয় getCurrentToken()এখন :-)
জিয়াও জিয়া

কল্পনাপ্রসূত ... এটি হ'ল ধরণের বিবরণ এবং উদাহরণ যা ডক্সে হওয়া উচিত!
এজেকিয়েল ভিক্টর

+1 টি। এই উত্তরটি ডেফিনিটিভ এএনটিএলআর 4 রেফারেন্স বইয়ের চেয়ে অনেক ভাল। এই উত্তরটি আদর্শ উদাহরণ সহ ধারণাটিতে স্পট।
asyncwait

11

আমি সর্বদা এএনটিএলআর এর সংক্ষিপ্ত রেফারেন্সটি আমার গাইড হিসাবে উইনসেন্ট.কম এ পূর্বাভাস ব্যবহার করেছি ।


6
হ্যাঁ, একটি দুর্দান্ত লিঙ্ক! তবে, যেমন আপনি উল্লেখ করেছেন, এএনটিএলআর-তে নতুন কেউ তুলনামূলকভাবে তুলনামূলকভাবে তুলনামূলকভাবে তুলনামূলকভাবে (তুলনামূলকভাবে) কিছুটা কঠিন হতে পারে। আমি কেবল আশা করি আমার উত্তর এএনটিএলআর-গ্রাস-হপারের জন্য আরও কিছুটা বন্ধুত্বপূর্ণ। :)
বার্ট কায়ার্স
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.