ด้านล่างคือการสาธิตที่ชื่นชอบ (ปัจจุบัน) ของฉันว่าเหตุใดการแยก C ++ จึงเป็นทัวริงที่สมบูรณ์เนื่องจากแสดงโปรแกรมที่ถูกต้องทางไวยากรณ์ถ้าจำนวนเต็มที่กำหนดนั้นมีค่าเฉพาะ
ดังนั้นฉันจึงยืนยันว่าC ++ นั้นไม่มีบริบทและไม่มีความอ่อนไหวต่อบริบทจะไม่บริบทฟรีมิได้ตามบริบท
หากคุณอนุญาตให้ใช้ลำดับสัญลักษณ์โดยพลการทั้งสองด้านของการผลิตใด ๆ คุณจะสร้างไวยากรณ์ Type-0 ("ไม่ จำกัด ") ในลำดับชั้น Chomskyซึ่งมีประสิทธิภาพมากกว่าไวยากรณ์ไวตามบริบท ไวยากรณ์ไม่ จำกัด เป็นทัวริงสมบูรณ์ ไวยากรณ์บริบท (Type-1) อนุญาตให้ใช้สัญลักษณ์หลายบริบทบนด้านซ้ายมือของการผลิต แต่บริบทเดียวกันจะต้องปรากฏบนด้านขวามือของการผลิต (ดังนั้นชื่อ "บริบทที่มีความสำคัญ") [1] ไวยากรณ์ไวต่อบริบทเทียบเท่ากับเครื่องทัวริงเชิงเส้นตรงเครื่องจักรทัวริงเชิงเส้นล้อมรอบ
ในโปรแกรมตัวอย่างการคำนวณที่สำคัญสามารถทำได้โดยเครื่องทัวริงแบบ จำกัด ขอบเขตดังนั้นจึงไม่ได้พิสูจน์ความเท่าเทียมกันของทัวริง แต่ส่วนที่สำคัญคือ parser จำเป็นต้องทำการคำนวณเพื่อทำการวิเคราะห์เชิงวากยสัมพันธ์ อาจมีการคำนวณใด ๆ ที่แสดงว่าเป็นการสร้างอินสแตนซ์ของเท็มเพลตและมีเหตุผลทุกประการที่เชื่อว่าการสร้างอินสแตนซ์ของเทมเพลต C ++ นั้นสมบูรณ์แบบที่ทัวริงสมบูรณ์ ดูตัวอย่างกระดาษ 2003 ของ Todd L. Veldhuizenกระดาษ
ไม่ว่า C + + จะแยกวิเคราะห์โดยคอมพิวเตอร์ได้หรือไม่ดังนั้นจึงสามารถแยกวิเคราะห์ได้โดยใช้เครื่องทัวริง ดังนั้นไวยากรณ์ที่ไม่ จำกัด สามารถจดจำได้ จริงๆแล้วการเขียนไวยกรณ์ดังกล่าวจะไม่สามารถใช้งานได้ซึ่งเป็นสาเหตุที่มาตรฐานไม่พยายามทำเช่นนั้น (ดูด้านล่าง)
ปัญหาเกี่ยวกับ "ความกำกวม" ของการแสดงออกบางอย่างส่วนใหญ่เป็นปลาเฮอริ่งแดง ในการเริ่มต้นนั้นความคลุมเครือเป็นคุณสมบัติของไวยากรณ์เฉพาะไม่ใช่ภาษา แม้ว่าภาษานั้นสามารถพิสูจน์ได้ว่าไม่มีไวยากรณ์ที่ไม่คลุมเครือ แต่ก็สามารถรับรู้ได้ด้วยไวยากรณ์ที่ไม่มีบริบท แต่ก็ไม่มีบริบท ในทำนองเดียวกันหากไม่สามารถรับรู้ได้โดยไวยากรณ์ที่ไม่มีบริบท แต่สามารถรับรู้ได้โดยไวยากรณ์ที่ไวต่อบริบทมันจะคำนึงถึงบริบท ความกำกวมไม่เกี่ยวข้อง
แต่ในกรณีใด ๆ เช่นบรรทัดที่ 21 (เช่นauto b = foo<IsPrime<234799>>::typen<1>();
) ในโปรแกรมด้านล่างนิพจน์จะไม่ชัดเจนเลย พวกเขาจะแยกวิเคราะห์แตกต่างกันขึ้นอยู่กับบริบท ในการแสดงออกที่ง่ายที่สุดของปัญหาหมวดหมู่ทางไวยากรณ์ของตัวระบุบางอย่างจะขึ้นอยู่กับวิธีการที่พวกเขาได้รับการประกาศ (เช่นประเภทและฟังก์ชั่น) ซึ่งหมายความว่าภาษาทางการจะต้องตระหนักถึงความจริงที่ว่า โปรแกรมเดียวกันเหมือนกัน (ประกาศและใช้) ซึ่งสามารถจำลองได้ด้วยไวยากรณ์ "copy" ซึ่งเป็นไวยากรณ์ที่สามารถจดจำคำที่เหมือนกันสองชุดติดต่อกัน มันง่ายที่จะพิสูจน์ด้วยบทแทรกว่าภาษานี้ไม่มีบริบท สามารถใช้ไวยากรณ์ไวตามบริบทสำหรับภาษานี้และไวยากรณ์ Type-0 มีให้ในคำตอบสำหรับคำถามนี้: /math/163830/context-sensitive-grammar-for-the- สำเนาภาษา
หากมีใครพยายามที่จะเขียนไวยากรณ์ที่ไวต่อบริบท (หรือไม่ จำกัด ) เพื่อแยก C ++ มันอาจจะเติมจักรวาลด้วยการขีดเขียน การเขียนเครื่องทัวริงเพื่อแยกซีพลัสพลัสจะเป็นไปไม่ได้เท่า ๆ กัน แม้แต่การเขียนโปรแกรม C ++ ก็เป็นเรื่องยากและเท่าที่ฉันรู้ว่าไม่มีใครได้รับการพิสูจน์ว่าถูกต้อง นี่คือเหตุผลที่มาตรฐานไม่ได้พยายามที่จะให้ไวยากรณ์ที่เป็นทางการที่สมบูรณ์และทำไมมันถึงเลือกที่จะเขียนกฎการแยกวิเคราะห์บางส่วนในภาษาอังกฤษทางเทคนิค
สิ่งที่ดูเหมือนไวยากรณ์ที่เป็นทางการในมาตรฐาน C ++ ไม่ใช่คำจำกัดความที่เป็นทางการของไวยากรณ์ของภาษา C ++ มันไม่ได้เป็นคำจำกัดความที่เป็นทางการของภาษาหลังจากการทำ preprocessing ซึ่งอาจทำให้เป็นทางการได้ง่ายขึ้น (นั่นไม่ใช่ภาษาแม้ว่า: ภาษา C ++ ตามที่กำหนดโดยมาตรฐานรวมถึงตัวประมวลผลล่วงหน้าและการดำเนินการของตัวประมวลผลล่วงหน้านั้นถูกอธิบายเป็นอัลกอริธึมเนื่องจากมันจะยากมากที่จะอธิบายในรูปแบบไวยากรณ์ใด ๆ มันอยู่ในส่วนนั้น ของมาตรฐานที่อธิบายการสลายตัวของคำศัพท์รวมถึงกฎที่จะต้องใช้มากกว่าหนึ่งครั้ง)
ไวยากรณ์ต่าง ๆ (สองไวยากรณ์ที่ทับซ้อนกันสำหรับการวิเคราะห์คำศัพท์ซึ่งจะเกิดขึ้นก่อนการประมวลผลก่อนและอื่น ๆ หากจำเป็นหลังจากนั้นบวกไวยากรณ์ "ไวยากรณ์") จะถูกเก็บรวบรวมในภาคผนวก A พร้อมหมายเหตุสำคัญนี้ (เน้นเพิ่มเติม):
บทสรุปของไวยากรณ์ C ++ นี้มีจุดประสงค์เพื่อช่วยในการเข้าใจ มันไม่ได้เป็นคำสั่งที่ถูกต้องของภาษา โดยเฉพาะอย่างยิ่งไวยากรณ์ที่อธิบายที่นี่ยอมรับsuperset ของที่ถูกต้อง c ++ สร้าง ต้องใช้กฎการลดความขัดแย้ง (6.8, 7.1, 10.2) เพื่อแยกแยะนิพจน์จากการประกาศ นอกจากนี้การควบคุมการเข้าถึงความคลุมเครือและกฎประเภทจะต้องใช้เพื่อกำจัดโครงสร้างที่ถูกต้อง แต่ไม่มีความหมาย
สุดท้ายนี่คือโปรแกรมที่สัญญาไว้ บรรทัดที่ 21 นั้นถูกต้องตามหลักไวยากรณ์ถ้าหาก N ในIsPrime<N>
นั้นเป็นไพร์ม มิฉะนั้นtypen
เป็นจำนวนเต็มไม่ใช่เทมเพลตดังนั้นจึงtypen<1>()
ถูกวิเคราะห์คำว่า(typen<1)>()
มีความผิดพลาดทางไวยากรณ์เนื่องจาก()
ไม่ได้เป็นนิพจน์ที่ถูกต้องทางไวยากรณ์
template<bool V> struct answer { answer(int) {} bool operator()(){return V;}};
template<bool no, bool yes, int f, int p> struct IsPrimeHelper
: IsPrimeHelper<p % f == 0, f * f >= p, f + 2, p> {};
template<bool yes, int f, int p> struct IsPrimeHelper<true, yes, f, p> { using type = answer<false>; };
template<int f, int p> struct IsPrimeHelper<false, true, f, p> { using type = answer<true>; };
template<int I> using IsPrime = typename IsPrimeHelper<!(I&1), false, 3, I>::type;
template<int I>
struct X { static const int i = I; int a[i]; };
template<typename A> struct foo;
template<>struct foo<answer<true>>{
template<int I> using typen = X<I>;
};
template<> struct foo<answer<false>>{
static const int typen = 0;
};
int main() {
auto b = foo<IsPrime<234799>>::typen<1>(); // Syntax error if not prime
return 0;
}
[1] เพื่อให้เป็นเทคนิคมากขึ้นทุกการผลิตในไวยากรณ์ไวตามบริบทจะต้องอยู่ในรูปแบบ:
αAβ → αγβ
ที่A
ไม่ใช่ขั้วและα
, β
เป็นลำดับอาจจะเป็นที่ว่างเปล่าของสัญลักษณ์ไวยากรณ์และγ
เป็นลำดับที่ไม่ว่างเปล่า (สัญลักษณ์ไวยากรณ์อาจเป็นเทอร์มินัลหรือไม่ใช่เทอร์มินัล)
สิ่งนี้สามารถอ่านได้A → γ
ในบริบท[α, β]
เท่านั้น ในไวยากรณ์ (ประเภท 2) ที่ไม่มีบริบทα
และβ
ต้องว่างเปล่า
ปรากฎว่าคุณสามารถ จำกัด ไวยากรณ์ด้วยข้อ จำกัด "โมโนโทนิก" ซึ่งการผลิตทุกอย่างจะต้องอยู่ในรูปแบบ:
α → β
โดยที่|α| ≥ |β| > 0
( |α|
หมายถึง "ความยาวของα
")
มีความเป็นไปได้ที่จะพิสูจน์ว่าชุดของภาษาที่ได้รับการยอมรับจากไวยากรณ์แบบโมโนโทนิกนั้นเหมือนกับชุดของภาษาที่ได้รับการยอมรับโดยแกรมม่าที่ไวต่อบริบทและบ่อยครั้งที่มันง่ายกว่า ดังนั้นมันจึงค่อนข้างธรรมดาที่จะเห็น "ไวต่อบริบท" ที่ใช้ราวกับว่ามันหมายถึง "เสียงเดียว"