จะเขียนล่ามคำสั่ง / parser ได้อย่างไร?


22

ปัญหา: เรียกใช้คำสั่งในรูปแบบของสตริง

  • ตัวอย่างคำสั่ง:

    /user/files/ list all; เทียบเท่ากับ: /user/files/ ls -la;

  • อีกอันหนึ่ง:

    post tw fb "HOW DO YOU STOP THE TICKLE MONSTER?;"

เทียบเท่ากับ: post -tf "HOW DO YOU STOP THE TICKLE MONSTER?;"

ทางออกปัจจุบัน:

tokenize string(string, array);

switch(first item in array) {
    case "command":
        if ( argument1 > stuff) {
           // do the actual work;
        }
}

ปัญหาที่ฉันเห็นในการแก้ปัญหานี้คือ:

  • ไม่มีข้อผิดพลาดในการตรวจสอบนอกจากซ้อน ifs-else ภายในแต่ละกรณี สคริปต์มีขนาดใหญ่มากและยากที่จะห้อมล้อม
  • คำสั่งและการตอบสนองจะฮาร์ดโค้ด
  • ไม่มีทางที่จะรู้ว่าการตั้งค่าสถานะเป็นพารามิเตอร์ที่ถูกต้องหรือขาดหายไป
  • ขาดความฉลาดในการแนะนำ "คุณอาจต้องการเรียกใช้คำสั่ง $"

และสิ่งสุดท้ายที่ฉันไม่สามารถบอกได้คือคำพ้องความหมายในการเข้ารหัสที่แตกต่างกันตัวอย่าง:

case command:
case command_in_hebrew:
    do stuff;
break;

อันสุดท้ายอาจเป็นเรื่องเล็กน้อย แต่สิ่งที่ฉันต้องการเห็นคือการระดมทุนที่แข็งแกร่งของโปรแกรมประเภทนี้

ฉันกำลังเขียนโปรแกรมนี้ใน PHP แต่อาจทำใน PERL


ฉันไม่เห็นเลยว่าสิ่งนี้เกี่ยวข้องกับ PHP โดยเฉพาะอย่างไร มีเธรดจำนวนมากในตัวแปล / คอมไพเลอร์ - หัวข้อนี้ใน SO และ SE แล้ว
Raffael

3
ไม่มีใครพูดถึง getopt?
Anton Barkovsky

@ AntonBarkovsky: ฉันทำ ดูลิงก์ของฉัน ฉันคิดว่าคำตอบเช่นเดียวกับ Ubermensch นั้นร้ายแรงเกินความซับซ้อนสำหรับสิ่งที่ OP พยายามทำ
quentin-starin

1
ฉันได้ยกวิธีง่าย ๆ โดยใช้ RegExp คำตอบจะได้รับการอัปเดตด้วย
Ubermensch

ไม่ได้พูดถึงโปรแกรมเฉพาะใด ๆ lang คุณสามารถเพิ่มแท็ก "c", "ruby" แท็ก, "php" แท็กอาจจะมี lib opensource, lib มาตรฐานหรือ "ที่ใช้กันทั่วไปยังไม่ได้เป็น lib มาตรฐาน" สำหรับ progr ของคุณ lang
umlcat

คำตอบ:


14

ให้ฉันยอมรับอย่างตรงไปตรงมาการสร้าง parser เป็นงานที่น่าเบื่อและใกล้เคียงกับเทคโนโลยีคอมไพเลอร์ แต่การสร้างหนึ่งจะกลายเป็นการผจญภัยที่ดี และโปรแกรมแยกวิเคราะห์มาพร้อมกับล่าม ดังนั้นคุณต้องสร้างทั้งคู่

การแนะนำตัวแยกวิเคราะห์และล่ามอย่างรวดเร็ว

นี่ไม่ใช่เทคนิคเกินไป ดังนั้นผู้เชี่ยวชาญจะไม่ทำให้ฉันหงุดหงิด

เมื่อคุณป้อนข้อมูลเข้าสู่เทอร์มินัลเทอร์มินัลจะแยกอินพุตเป็นหลาย ๆ หน่วย อินพุตถูกเรียกว่า expression และหลายหน่วยเรียกว่าโทเค็น โทเค็นเหล่านี้สามารถเป็นโอเปอเรเตอร์หรือสัญลักษณ์ ดังนั้นถ้าคุณป้อน4 + 5ในเครื่องคิดเลขนิพจน์นี้จะถูกแบ่งออกเป็นสามโทเค็น 4, +, 5 เครื่องหมายบวกถือเป็นโอเปอเรเตอร์ในขณะที่สัญลักษณ์ 4 และ 5 สิ่งนี้ถูกส่งผ่านไปยังโปรแกรม (ถือว่านี่เป็นล่าม) ซึ่งมีคำจำกัดความของโอเปอเรเตอร์ ขึ้นอยู่กับคำจำกัดความ (ในกรณีของเราเพิ่ม) มันเพิ่มสองสัญลักษณ์และส่งกลับผลลัพธ์ไปยังสถานี คอมไพเลอร์ทั้งหมดใช้เทคโนโลยีนี้ โปรแกรมที่แยกนิพจน์เป็นโทเค็นหลายตัวเรียกว่า lexer และโปรแกรมที่แปลงโทเค็นเหล่านี้เป็นแท็กสำหรับการประมวลผลเพิ่มเติมและการดำเนินการเรียกว่า parser

Lex และ Yaccเป็นรูปแบบบัญญัติสำหรับการสร้าง lexers และ parsers ตามไวยากรณ์BNFภายใต้ C และเป็นตัวเลือกที่แนะนำ โปรแกรมแยกวิเคราะห์ส่วนใหญ่เป็นโคลนของ Lex และ Yacc

ขั้นตอนในการสร้าง parser / intrepreter

  1. จำแนกโทเค็นของคุณเป็นสัญลักษณ์ตัวดำเนินการและคำหลัก (คำหลักคือตัวดำเนินการ)
  2. สร้างไวยากรณ์ของคุณโดยใช้แบบฟอร์ม BNF
  3. เขียนฟังก์ชันตัวแยกวิเคราะห์สำหรับการดำเนินการของคุณ
  4. รวบรวมมันทำงานเป็นโปรแกรม

ดังนั้นในกรณีข้างต้นโทเค็นเพิ่มเติมของคุณจะเป็นตัวเลขใด ๆ และเครื่องหมายบวกที่มีความหมายของสิ่งที่จะทำอย่างไรกับเครื่องหมายบวกใน lexer

หมายเหตุและเคล็ดลับ

  • เลือกเทคนิคการแยกวิเคราะห์ที่ประเมินจากซ้ายไปขวาLALR
  • อ่านหนังสือมังกรเล่มนี้ในคอมไพเลอร์เพื่อรับความรู้สึก โดยส่วนตัวฉันยังอ่านหนังสือไม่เสร็จ
  • ลิงค์นี้จะให้ข้อมูลเชิงลึกอย่างรวดเร็วเกี่ยวกับ Lex และ Yacc ภายใต้ Python

วิธีการง่ายๆ

หากคุณต้องการกลไกการแยกวิเคราะห์แบบง่ายที่มีฟังก์ชั่น จำกัด เปลี่ยนความต้องการของคุณให้เป็นนิพจน์ปกติและสร้างฟังก์ชั่นทั้งหมด เพื่อแสดงให้เห็นถึงสมมติตัวแยกวิเคราะห์อย่างง่ายสำหรับสี่ฟังก์ชั่นทางคณิตศาสตร์ ดังนั้นคุณจะต้องโทรหาโอเปอเรเตอร์ก่อนแล้วจึงทำรายการฟังก์ชั่น (คล้ายกับเสียงกระเพื่อม) ในรูปแบบ(+ 4 5)หรือ(add [4,5])จากนั้นคุณสามารถใช้ RegExp อย่างง่าย ๆ เพื่อรับรายชื่อของโอเปอเรเตอร์และสัญลักษณ์ต่างๆ

กรณีทั่วไปส่วนใหญ่สามารถแก้ไขได้อย่างง่ายดายโดยวิธีนี้ ข้อเสียคือคุณไม่สามารถมีนิพจน์ที่ซ้อนกันจำนวนมากที่มีไวยากรณ์ที่ชัดเจนและคุณไม่สามารถมีฟังก์ชั่นการสั่งซื้อที่สูงขึ้นได้ง่าย


2
นี่เป็นวิธีที่ยากที่สุดวิธีหนึ่งที่เป็นไปได้ การแยก lexing และ parsing pass ฯลฯ - มันอาจเป็นประโยชน์สำหรับการใช้ parser ประสิทธิภาพสูงสำหรับภาษาที่ซับซ้อนมาก แต่เป็นภาษาโบราณ ในโลกสมัยใหม่การแยกวิเคราะห์ lexerless เป็นตัวเลือกเริ่มต้นที่ง่ายที่สุด การแยก combinators หรือ eDSL นั้นง่ายกว่าการใช้ preprocessors เฉพาะอย่างเช่น Yacc
SK-logic

เห็นด้วยกับ SK-logic แต่เนื่องจากต้องการคำตอบโดยละเอียดฉันจึงแนะนำ Lex และ Yacc และพื้นฐาน parser getopts ที่ Anton แนะนำนั้นเป็นตัวเลือกที่ง่ายกว่า
Ubermensch

นั่นคือสิ่งที่ฉันพูด - lex และ yacc เป็นหนึ่งในวิธีที่ยากที่สุดในการแยกวิเคราะห์และไม่แม้แต่ทั่วไปพอ การแยกวิเคราะห์แบบ Lexerless (เช่น packrat หรือ Parsec แบบง่าย ๆ ) นั้นง่ายกว่ามากสำหรับกรณีทั่วไป และหนังสือมังกรไม่ได้มีประโยชน์ในการแยกวิเคราะห์อีกต่อไป - มันล้าสมัยเกินไป
SK-logic

@ SK-logic คุณช่วยแนะนำหนังสือที่ปรับปรุงให้ดีขึ้นได้ไหม ดูเหมือนจะครอบคลุมพื้นฐานทั้งหมดสำหรับคนที่พยายามเข้าใจการแยกวิเคราะห์ (อย่างน้อยก็ในการรับรู้ของฉัน) เกี่ยวกับ lex และ yacc แม้ว่าจะยาก แต่ก็มีการใช้กันอย่างแพร่หลายและภาษาการเขียนโปรแกรมจำนวนมากให้การใช้งาน
Ubermensch

1
@ alfa64: อย่าลืมแจ้งให้เราทราบเมื่อคุณเขียนรหัสทางออกตามคำตอบนี้
quentin-starin

7

อันดับแรกเมื่อพูดถึงเรื่องไวยากรณ์หรือวิธีระบุอาร์กิวเมนต์อย่าประดิษฐ์ของคุณเอง มาตรฐาน GNU สไตล์ที่มีอยู่แล้วเป็นที่นิยมมากและรู้จักกันดี

ประการที่สองเนื่องจากคุณใช้มาตรฐานที่ยอมรับได้อย่าดัดแปลงล้อ ใช้ห้องสมุดที่มีอยู่เพื่อทำเพื่อคุณ หากคุณใช้อาร์กิวเมนต์สไตล์ของ GNU แสดงว่ามีไลบรารีผู้ใหญ่ในภาษาที่คุณเลือกอยู่แล้ว ตัวอย่างเช่น: C # , PHP , C

ตัวเลือกที่ดีในการแยกวิเคราะห์ไลบรารี่จะพิมพ์รูปแบบการช่วยเหลือบนตัวเลือกที่มีให้คุณ

แก้ไข 12/27

ดูเหมือนว่าคุณกำลังทำให้เรื่องนี้ซับซ้อนกว่าที่เป็นอยู่

เมื่อคุณดูบรรทัดคำสั่งมันง่ายมาก ๆ เป็นเพียงตัวเลือกและข้อโต้แย้งสำหรับตัวเลือกเหล่านั้น มีปัญหาที่ซับซ้อนน้อยมาก ตัวเลือกสามารถมีนามแฝง อาร์กิวเมนต์สามารถเป็นรายการของอาร์กิวเมนต์

ปัญหาหนึ่งสำหรับคำถามของคุณคือคุณไม่ได้ระบุกฎใด ๆ สำหรับบรรทัดคำสั่งประเภทใดที่คุณต้องการจัดการ ฉันแนะนำมาตรฐาน GNU และตัวอย่างของคุณใกล้เคียงกับนั้น (ถึงแม้ว่าฉันจะไม่เข้าใจตัวอย่างแรกของคุณด้วยเส้นทางเป็นรายการแรก)

หากเรากำลังพูดถึง GNU ตัวเลือกใด ๆ สามารถมีรูปแบบยาวและแบบสั้น (อักขระเดียว) เป็นนามแฝง อาร์กิวเมนต์ใด ๆ ที่มีช่องว่างจะต้องล้อมรอบด้วยเครื่องหมายคำพูด ตัวเลือกแบบฟอร์มสั้น ๆ หลายตัวสามารถถูกล่ามโซ่ ตัวเลือกรูปแบบสั้น ๆ จะต้องดำเนินการโดยเส้นประเดียวแบบยาวโดยสองขีดกลาง เฉพาะตัวเลือกแบบฟอร์มสั้นสุดที่ผ่านการผูกมัดเท่านั้นที่สามารถมีอาร์กิวเมนต์

ตรงไปตรงมามาก ทั้งหมดเป็นเรื่องธรรมดามาก นอกจากนี้ยังมีการใช้งานในทุกภาษาที่คุณสามารถค้นหาได้ซึ่งอาจมากกว่าห้าครั้ง

อย่าเขียนมัน ใช้สิ่งที่เขียนไปแล้ว

ยกเว้นว่าคุณมีบางอย่างในใจนอกเหนือจากอาร์กิวเมนต์บรรทัดคำสั่งมาตรฐานเพียงใช้หนึ่งในหลาย ๆ ไลบรารีที่มีอยู่และทดสอบแล้วซึ่งทำสิ่งนี้

โรคแทรกซ้อนคืออะไร?


3
ใช้ประโยชน์จากชุมชนโอเพนซอร์สเสมอ
Spencer Rathbun

คุณลอง getoptionkit แล้วหรือยัง
alfa64

ไม่ฉันไม่ได้ทำงานเป็น PHP ในเวลาไม่กี่ปี อาจมี php ไลบรารี่อื่นด้วยเช่นกัน ฉันใช้ไลบรารีตัวแยกวิเคราะห์บรรทัดคำสั่ง c # ที่ฉันลิงก์ไปแล้ว
quentin-starin

4

คุณได้ลองทำอะไรเช่นhttp://qntm.org/loco แล้ว ? วิธีการนี้สะอาดกว่า ad hoc แบบเขียนด้วยมือ แต่ไม่จำเป็นต้องใช้เครื่องมือสร้างรหัสแบบสแตนด์อโลนเช่น Lemon

แก้ไข:และเคล็ดลับทั่วไปสำหรับการจัดการบรรทัดคำสั่งกับไวยากรณ์ที่ซับซ้อนคือการรวมอาร์กิวเมนต์กลับเข้าไปในสตริงที่คั่นด้วยช่องว่างเดียวแล้วแยกวิเคราะห์อย่างถูกต้องราวกับว่ามันเป็นการแสดงออกของภาษาเฉพาะโดเมนบางส่วน


+1 ลิ้งค์ดีฉันสงสัยว่ามันมีใน GitHub หรืออย่างอื่น และสิ่งที่เกี่ยวกับเงื่อนไขการใช้งาน?
hakre

1

คุณยังไม่ได้ระบุรายละเอียดเกี่ยวกับไวยากรณ์ไว้มากมายตัวอย่าง สิ่งที่ฉันเห็นคือมีสตริงบางส่วนช่องว่างและ (อาจเป็นตัวอย่างของคุณไม่สนใจคำถามของคุณ) สตริงที่ยกมาสองครั้งแล้วหนึ่ง ";" ในตอนท้าย

ดูเหมือนว่าสิ่งนี้อาจคล้ายกับไวยากรณ์ PHP ถ้าเป็นเช่นนั้น PHP มาพร้อมกับ parser คุณสามารถนำกลับมาใช้ใหม่และตรวจสอบได้อย่างเป็นรูปธรรมยิ่งขึ้น ในที่สุดคุณจำเป็นต้องจัดการกับโทเค็น แต่ดูเหมือนว่านี่เป็นเพียงจากซ้ายไปขวาดังนั้นจริง ๆ แล้วเพียงแค่วนซ้ำของโทเค็นทั้งหมด

ตัวอย่างบางส่วนที่จะใช้ PHP token parser ( token_get_all) อีกครั้งจะได้รับคำตอบสำหรับคำถามต่อไปนี้:

ทั้งสองตัวอย่างมีตัวแยกวิเคราะห์อย่างง่ายเช่นกันอาจเป็นสิ่งที่เหมาะสมกับสถานการณ์ของคุณ


ใช่ฉันรีบเร่งเรื่องไวยากรณ์ฉันจะเพิ่มทันที
alfa64

1

หากความต้องการของคุณนั้นเรียบง่ายและคุณทั้งคู่มีเวลาและมีความสนใจในเรื่องนั้นฉันจะไปต่อต้านเมล็ดข้าวที่นี่และพูดว่าอย่าอายไปจากการเขียนโปรแกรมแยกวิเคราะห์ของคุณเอง มันเป็นประสบการณ์การเรียนรู้ที่ดีถ้าไม่มีอะไรอื่น หากคุณมีข้อกำหนดที่ซับซ้อนมากขึ้น - การเรียกใช้ฟังก์ชันที่ซ้อนกันอาร์เรย์และอื่น ๆ - โปรดทราบว่าการทำเช่นนั้นอาจใช้เวลานาน ข้อดีอย่างหนึ่งของการม้วนตัวของคุณเองก็คือจะไม่มีปัญหาในการรวมเข้ากับระบบของคุณ ข้อเสียคือแน่นอนว่าสกรูทั้งหมดเป็นความผิดของคุณ

ทำงานกับโทเค็น แต่อย่าใช้คำสั่งที่เข้ารหัสยาก จากนั้นปัญหาที่เกิดขึ้นกับคำสั่งการทำให้เกิดเสียงที่คล้ายกันก็หายไป

ทุกคนแนะนำหนังสือมังกรเสมอ แต่ฉันพบเสมอว่า"การเขียนคอมไพเลอร์และล่าม"โดย Ronald Mak เพื่อเป็นอินโทรที่ดีกว่า


0

ฉันได้เขียนโปรแกรมที่ทำงานเช่นนั้น หนึ่งคือบอท IRC ซึ่งมีไวยากรณ์คำสั่งที่คล้ายกัน มีไฟล์ขนาดใหญ่ที่เป็นคำสั่งสวิตช์ขนาดใหญ่ มันใช้งานได้ - ทำงานได้อย่างรวดเร็ว - แต่มันค่อนข้างยากที่จะบำรุงรักษา

ตัวเลือกอื่นซึ่งมีการหมุน OOP มากขึ้นคือการใช้ตัวจัดการเหตุการณ์ คุณสร้างคีย์ - ค่า - อาร์เรย์พร้อมคำสั่งและฟังก์ชันเฉพาะของพวกเขา เมื่อได้รับคำสั่งคุณตรวจสอบว่าอาร์เรย์มีคีย์ที่กำหนดหรือไม่ ถ้าเป็นเช่นนั้นให้เรียกใช้ฟังก์ชัน นี่จะเป็นคำแนะนำของฉันสำหรับรหัสใหม่


ฉันได้อ่านรหัสของคุณแล้วและมันก็เป็นแบบเดียวกับรหัสของฉัน แต่ตามที่ฉันระบุถ้าคุณต้องการให้คนอื่นใช้คุณต้องเพิ่มการตรวจสอบข้อผิดพลาดและสิ่งต่าง ๆ
alfa64

1
@ alfa64 โปรดเพิ่มคำอธิบายใด ๆ ให้กับคำถามแทนที่จะเป็นความคิดเห็น ไม่ชัดเจนมากว่าคุณขออะไร แต่ก็ค่อนข้างชัดเจนว่าคุณกำลังมองหาบางสิ่งที่เฉพาะเจาะจงจริงๆ ถ้าเป็นเช่นนั้นบอกเราว่าสิ่งที่เป็น ผมไม่คิดว่ามันเป็นเรื่องง่ายมากที่จะไปจากI think my implementation is very crude and faultyไปbut as i stated, if you want other people to use, you need to add error checking and stuff... บอกให้เราทราบว่าสิ่งที่มันดิบเกี่ยวกับมันและสิ่งที่ผิดพลาดก็จะช่วยให้คุณได้คำตอบที่ดี
yannis

แน่นอนฉันจะทำใหม่คำถาม
alfa64

0

ฉันแนะนำให้ใช้เครื่องมือแทนการใช้คอมไพเลอร์หรือล่ามเอง Irony ใช้ C # เพื่อแสดงไวยากรณ์ภาษาเป้าหมาย (ไวยากรณ์ของบรรทัดคำสั่งของคุณ) คำอธิบายเกี่ยวกับ CodePlex พูดว่า: "Irony เป็นชุดพัฒนาสำหรับการนำภาษาไปใช้บนแพลตฟอร์ม. NET"

ดูเว็บไซต์อย่างเป็นทางการของการประชดใน CodePlex: Irony - .NET ภาษาชุดการดำเนินงาน


คุณจะใช้กับ PHP อย่างไร?
SK-logic

ฉันไม่เห็นแท็ก PHP หรืออ้างอิงถึง PHP ในคำถาม
Olivier Jacot-Descombes

ฉันเคยเห็นมันเคยเป็นเรื่องเกี่ยวกับ PHP มาก่อน แต่ตอนนี้เขียนใหม่
SK-logic

0

คำแนะนำของฉันจะเป็น google สำหรับห้องสมุดที่แก้ปัญหาของคุณ

เมื่อเร็ว ๆ นี้ฉันใช้ NodeJS มากและOptimistเป็นสิ่งที่ฉันใช้สำหรับการประมวลผลบรรทัดคำสั่ง ฉันขอแนะนำให้คุณค้นหาภาษาที่คุณสามารถใช้สำหรับภาษาที่คุณเลือกเอง ถ้าไม่ .. เขียนหนึ่งอันและโอเพ่นซอร์ส: D คุณสามารถอ่านได้จากซอร์สโค้ดของ Optimist และเชื่อมต่อกับภาษาที่คุณเลือก


0

ทำไมคุณไม่ทำให้ความต้องการของคุณเล็กน้อยง่ายขึ้น?

อย่าใช้เครื่องมือแยกวิเคราะห์เต็มรูปแบบซับซ้อนเกินไปและไม่จำเป็นสำหรับกรณีของคุณ

ทำให้วนเขียนข้อความที่แสดงถึง yout "prompt" สามารถเป็นเส้นทางปัจจุบันที่คุณอยู่

รอให้สตริง "แยกวิเคราะห์" สตริงและทำบางสิ่งบางอย่างขึ้นอยู่กับเนื้อหาของสตริง

สตริงสามารถ "แยกวิเคราะห์" เช่นเดียวกับที่คาดว่าจะมีบรรทัดซึ่งช่องว่างเป็นตัวคั่น ("tokenizer") และอักขระส่วนที่เหลือจะถูกจัดกลุ่ม

ตัวอย่าง.

โปรแกรมแสดงผล (และอยู่ในบรรทัดเดียวกัน): / user / files / ผู้ใช้เขียนรายการ (ในบรรทัดเดียวกัน) ทั้งหมด;

โปรแกรมของคุณจะสร้างรายการคอลเลกชันหรืออาร์เรย์เช่น

list

all;

หรือถ้า ";" ถือเป็นตัวคั่นเช่นช่องว่าง

/user/files/

list

all

โปรแกรมของคุณสามารถเริ่มต้นได้ด้วยการคาดหวังคำสั่งเดียวโดยไม่ต้องใช้ "ไพพ์" แบบ unix และไม่มีการเปลี่ยนทิศทางสไตล์หน้าต่าง

โปรแกรมของคุณสามารถสร้างพจนานุกรมคำแนะนำแต่ละคำสั่งอาจมีรายการพารามิเตอร์

รูปแบบการออกแบบคำสั่งใช้กับกรณีของคุณ:

http://en.wikipedia.org/wiki/Command_pattern

pseudocode "c ธรรมดา" นี้ไม่ได้ทดสอบหรือเสร็จสิ้นเป็นเพียงความคิดว่าสามารถทำได้อย่างไร

คุณสามารถทำให้มันเป็นวัตถุเชิงวัตถุมากขึ้นและในภาษาการเขียนโปรแกรมคุณชอบ

ตัวอย่าง:


// "global function" pointer type declaration
typedef
  void (*ActionProc) ();

struct Command
{
  char[512] Identifier;
  ActionProc Action; 
};

// global var declarations

list<char*> CommandList = new list<char*>();
list<char*> Tokens = new list<char*>();

void Action_ListDirectory()
{
  // code to list directory
} // Action_ListDirectory()

void Action_ChangeDirectory()
{
  // code to change directory
} // Action_ChangeDirectory()

void Action_CreateDirectory()
{
  // code to create new directory
} // Action_CreateDirectory()

void PrepareCommandList()
{
  CommandList->Add("ls", &Action_ListDirectory);
  CommandList->Add("cd", &Action_ChangeDirectory);
  CommandList->Add("mkdir", &Action_CreateDirectory);

  // register more commands
} // void PrepareCommandList()

void interpret(char* args, int *ArgIndex)
{
  char* Separator = " ";
  Tokens = YourSeparateInTokensFunction(args, Separator);

  // "LocateCommand" may be case sensitive
  int AIndex = LocateCommand(CommandList, args[ArgIndex]);
  if (AIndex >= 0)
  {
    // the command

    move to the next parameter
    *ArgIndex = (*ArgIndex + 1);

    // obtain already registered command
    Command = CommandList[AIndex];

    // execute action
    Command.Action();
  }
  else
  {
    puts("some kind of command not found error, or, error syntax");
  }  
} // void interpret()

void main(...)
{
  bool CanContinue = false;
  char* Prompt = "c\:>";

  char Buffer[512];

  // which command line parameter string is been processed
  int ArgsIndex = 0;

  PrepareCommandList();

  do
  {
    // display "prompt"
    puts(Prompt);
    // wait for user input
      fgets(Buffer, sizeof(Buffer), stdin);

    interpret(buffer, &ArgsIndex);

  } while (CanContinue);

} // void main()

คุณไม่ได้พูดถึงภาษาการเขียนโปรแกรมของคุณ คุณยังสามารถพูดถึงภาษาการเขียนโปรแกรมใด ๆ แต่ควร "XYZ"


0

คุณมีงานหลายอย่างที่อยู่ข้างหน้าคุณ

ดูความต้องการของคุณ ...

  • คุณต้องแยกวิเคราะห์คำสั่ง นั่นเป็นงานที่ค่อนข้างง่าย
  • คุณต้องมีภาษาคำสั่งที่ขยายออกได้
  • คุณต้องมีการตรวจสอบข้อผิดพลาดและข้อเสนอแนะ

ภาษาคำสั่งที่ขยายได้บ่งชี้ว่าจำเป็นต้องใช้ DSL ฉันจะแนะนำไม่ให้กลิ้งเอง แต่ใช้ JSON หากส่วนขยายของคุณเรียบง่าย หากมันซับซ้อนไวยากรณ์ของ s-expression นั้นดี

การตรวจสอบข้อผิดพลาดหมายความว่าระบบของคุณยังรู้เกี่ยวกับคำสั่งที่เป็นไปได้ นั่นจะเป็นส่วนหนึ่งของระบบหลังคำสั่ง

หากฉันใช้ระบบดังกล่าวตั้งแต่เริ่มต้นฉันจะใช้ Common LISP กับเครื่องอ่านแบบถอดสาย โทเค็นคำสั่งแต่ละอันจะแม็พกับสัญลักษณ์ซึ่งจะระบุในไฟล์ s-expression RC หลังจาก tokenization มันจะได้รับการประเมิน / ขยายในบริบทที่ จำกัด กับดักข้อผิดพลาดและรูปแบบข้อผิดพลาดที่รู้จักได้จะกลับคำแนะนำ หลังจากนั้นคำสั่งจริงจะถูกส่งไปยังระบบปฏิบัติการ


0

มีคุณสมบัติที่ดีในการเขียนโปรแกรมฟังก์ชั่นที่คุณอาจสนใจดู

มันเรียกว่ารูปแบบการจับคู่

ที่นี่สองเชื่อมโยงตัวอย่างเช่นบางส่วนของการจับคู่ในรูปแบบที่มีScalaและF #

ฉันเห็นด้วยกับคุณว่าการใช้switchโครงสร้างเป็นสิ่งที่น่าเบื่อและฉันสนุกเป็นอย่างยิ่งโดยใช้การจับคู่พ่อกับการใช้คอมไพเลอร์ใน Scala

โดยเฉพาะอย่างยิ่งฉันขอแนะนำให้คุณดูตัวอย่างแคลคูลัสแลมบ์ดาของเว็บไซต์สกาล่า

ว่าในความคิดของฉันวิธีที่ฉลาดในการดำเนินการ แต่ถ้าคุณต้องติดอย่างเคร่งครัดด้วย PHP แล้วคุณติดอยู่กับ switch"โรงเรียนเก่า"


0

ลองใช้งานApache CLIมันมีจุดประสงค์ทั้งหมดเพื่อให้คุณทำในสิ่งที่คุณต้องการดังนั้นแม้ว่าคุณจะไม่สามารถใช้งานได้คุณก็สามารถตรวจสอบสถาปัตยกรรมและคัดลอกมันได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.