আমি এটিকে সাধারণ লোকের শর্তে রেখে ছুরিকাঘাত করব।
আপনি যদি পার্স গাছের কথা বিবেচনা করেন (এএসটি নয়, তবে পার্সারের পরিদর্শন এবং ইনপুটটির বিস্তৃতি), বাম পুনরাবৃত্তির ফলে গাছটি বাম এবং নীচের দিকে বৃদ্ধি পায় grows ডান পুনরাবৃত্তি ঠিক বিপরীত।
উদাহরণস্বরূপ, সংকলকটিতে একটি সাধারণ ব্যাকরণ হ'ল আইটেমগুলির তালিকা। স্ট্রিংগুলির একটি তালিকা ("লাল", "সবুজ", "নীল") নিতে এবং এটি বিশ্লেষণ করতে দেয়। আমি ব্যাকরণ কয়েকভাবে লিখতে পারতাম। নিম্নলিখিত উদাহরণগুলি যথাক্রমে সরাসরি বাম বা ডান পুনরাবৃত্ত হয়:
arg_list: arg_list:
STRING STRING
| arg_list ',' STRING | STRING ',' arg_list
এই পার্সের জন্য গাছগুলি:
(arg_list) (arg_list)
/ \ / \
(arg_list) BLUE RED (arg_list)
/ \ / \
(arg_list) GREEN GREEN (arg_list)
/ /
RED BLUE
এটি পুনরাবৃত্তির দিকের দিকে কীভাবে বৃদ্ধি পায় তা নোট করুন।
এটি আসলে কোনও সমস্যা নয়, একটি বাম রিকার্সিভ ব্যাকরণ লিখতে চান ঠিক ... আপনার পার্সার সরঞ্জাম যদি এটি পরিচালনা করতে পারে। নীচে পার্সারগুলি এটি ঠিকঠাক করে। সুতরাং আরও আধুনিক এলএল পার্সারগুলি করতে পারেন। রিকার্সিভ ব্যাকরণগুলির সমস্যাটি পুনরাবৃত্তি নয়, এটি পার্সারকে অগ্রসর না করে পুনরুক্তি করা বা টোকেন গ্রহণ না করে পুনরাবৃত্তি করা। আমরা পুনরাবৃত্তি করার সময় যদি আমরা সর্বদা কমপক্ষে 1 টোকেন গ্রাস করি, তবে আমরা শেষ পর্যন্ত পার্সের শেষে পৌঁছে যাই। বাম পুনরাবৃত্তি বিনা ব্যতীত পুনরাবৃত্তি হিসাবে সংজ্ঞায়িত করা হয়, যা একটি অসীম লুপ।
এই সীমাবদ্ধতা নিখুঁত শীর্ষ-ডাউন এলএল পার্সার (পুনরাবৃত্তীয় বংশদ্ভুত পার্সার) সহ একটি ব্যাকরণ বাস্তবায়নের বিশদভাবে বিশ্লেষণের বিশদ। আপনি যদি বাম রিকার্সিভ ব্যাকরণগুলির সাথে লেগে থাকতে চান, তবে পুনরাবৃত্তি করার আগে কমপক্ষে 1 টোকেন খাওয়ার জন্য উত্পাদনটি পুনর্লিখন করে আপনি এটি মোকাবেলা করতে পারেন, সুতরাং এটি নিশ্চিত করে যে আমরা কখনই অ উত্পাদনশীল লুপে আটকে যাব না। বাম-পুনরাবৃত্তিমূলক যে কোনও ব্যাকরণের নিয়মের জন্য, আমরা একটি মধ্যবর্তী নিয়ম যুক্ত করে এটি পুনরায় লিখতে পারি যা ব্যাকরণকে কেবলমাত্র এক স্তরের রূপায়িত করে পুনরাবৃত্ত প্রযোজনার মধ্যে টোকেন গ্রহণ করে। (দ্রষ্টব্য: আমি ব্যাকরণটি পুনর্লিখনের একমাত্র উপায় বা পছন্দসই উপায় এটিই বলছি না, কেবল সাধারণীকরণের নিয়মটি নির্দেশ করে this এই সাধারণ উদাহরণে, সঠিক বিকল্পটি ডান রিকার্সিভ ফর্মটি ব্যবহার করা)। যেহেতু এই পদ্ধতিটি সাধারণীকরণযোগ্য, কোনও পার্সার জেনারেটর প্রোগ্রামারকে (তাত্ত্বিকভাবে) জড়িত না করে এটি প্রয়োগ করতে পারে। অনুশীলনে, আমি বিশ্বাস করি এএনটিএলআর 4 এখন এটিই করে।
উপরের ব্যাকরণের জন্য, বাম পুনরাবৃত্তি প্রদর্শন করা এলএল বাস্তবায়নটি এর মতো দেখায়। পার্সার একটি তালিকা পূর্বাভাস দিয়ে শুরু হবে ...
bool match_list()
{
if(lookahead-predicts-something-besides-comma) {
match_STRING();
} else if(lookahead-is-comma) {
match_list(); // left-recursion, infinite loop/stack overflow
match(',');
match_STRING();
} else {
throw new ParseException();
}
}
বাস্তবে, আমরা যা সত্যিই মোকাবেলা করছি তা হ'ল "নিষ্পাপ বাস্তবায়ন", অর্থাৎ। আমরা প্রথমে একটি প্রদত্ত বাক্য পূর্বাভাস দিয়েছিলাম, তারপরে পুনরাবৃত্তভাবে সেই ভবিষ্যদ্বাণীটির জন্য ফাংশনটি বলেছিলাম এবং সেই ফাংশনটি নির্বোধভাবে আবার সেই একই ভবিষ্যদ্বাণীটিকে কল করে।
নীচের অংশীদারদের উভয় দিকেই পুনরাবৃত্ত নিয়মের সমস্যা নেই, কারণ তারা বাক্যটির শুরুটিকে পৃথক করে না, তারা বাক্যটি আবার একসাথে রেখে কাজ করে।
ব্যাকরণে পুনরাবৃত্তি কেবল তখনই সমস্যা হয় যদি আমরা উপরে থেকে নীচে উত্পাদন করি, অর্থাৎ। আমাদের পার্সার টোকেন গ্রহণ করার সাথে সাথে আমাদের পূর্বাভাসগুলি "প্রসারিত" করে কাজ করে। যদি প্রসারণের পরিবর্তে, আমরা ভেঙে যাই (প্রযোজনাগুলি "হ্রাস" হয়) যেমনটি এলএলআর (ইয়্যাক / বাইসন) নীচে আপ পার্সারের মতো হয়, তবে উভয় পক্ষের পুনরাবৃত্তি কোনও সমস্যা নয়।
::=
থেকেExpression
থেকেTerm
, এবং যদি আপনি প্রথম পর একই করেনি||
এটি আর বাম-রিকার্সিভ হবে? তবে আপনি যদি এটি কেবল পরে করেন::=
তবে তা না||
, এটি এখনও বাম-পুনরাবৃত্তি হবে?