C ++ ไม่มีบริบทหรือคำนึงถึงบริบทหรือไม่


405

ฉันมักจะได้ยินคำกล่าวอ้างว่า C ++ เป็นภาษาที่คำนึงถึงบริบท นำตัวอย่างต่อไปนี้:

a b(c);

นี่เป็นคำนิยามตัวแปรหรือการประกาศฟังก์ชันหรือไม่ cที่ขึ้นอยู่กับความหมายของสัญลักษณ์ ถ้าcเป็นตัวแปรแล้วa b(c);กำหนดชื่อตัวแปรประเภทb มันจะเริ่มต้นได้โดยตรงกับa cแต่ถ้าcเป็นประเภทแล้วa b(c);ประกาศฟังก์ชั่นที่มีชื่อbที่ใช้และส่งกลับca

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

การเรียกดูผ่านภาคผนวก A ของ "ภาษาการเขียนโปรแกรม C ++" ฉันไม่สามารถหากฎไวยากรณ์เดียวที่มีสิ่งอื่นนอกเหนือจากสัญลักษณ์ที่ไม่ใช่เทอร์มินัลเดียวที่ด้านซ้ายมือ นั่นหมายความว่า C ++ นั้นไม่มีบริบท (แน่นอนว่าภาษาที่ไม่มีบริบททุกภาษานั้นมีความอ่อนไหวตามบริบทด้วยในแง่ที่ว่าภาษาที่ไม่ใช้บริบทนั้นเป็นส่วนย่อยของภาษาที่คำนึงถึงบริบท แต่นั่นไม่ใช่ประเด็น)

ดังนั้น C ++ ไม่มีบริบทหรือตามบริบทหรือไม่


12
@CarlNorum โปรดแสดงกฎไวยากรณ์เดียวของ C ++ ที่ไม่ประกอบด้วยสัญลักษณ์ที่ไม่ใช่เทอร์มินัลเดียวทางซ้ายมือและฉันจะเชื่อคุณทันที
fredoverflow

9
IIUC มันขึ้นอยู่กับว่าคุณวาดเส้นเพื่อไวต่อบริบทหรือไม่ ฉันคิดว่าฉันเคยเห็นผู้คนให้เหตุผลว่าเกือบทุกภาษาที่เขียนโปรแกรมแบบคงที่นั้นมีความไวต่อบริบทไม่ใช่เพราะคุณไม่สามารถสร้างคอมไพเลอร์ที่ใช้งานได้จริงด้วยเครื่องมือวิเคราะห์ CFG แต่เพราะการใช้งานเช่น "โกง" ปฏิเสธเฉพาะในภายหลังในระหว่างการตรวจสอบประเภท ดังนั้นหากคุณพิจารณาว่าโปรแกรมที่ไม่ถูกต้องไม่อยู่ในภาษา (ในความหมาย CS คือชุดของสตริง) โปรแกรมแยกวิเคราะห์ควรยอมรับภาษามากกว่า C ++ จะคำนึงถึงบริบท

6
@DeadMG: ไม่คุณผิด ไม่มี "การวิเคราะห์คำ" หรือ "ความหมาย" ในทฤษฎีภาษาที่เป็นทางการเลยเพียงแค่ "ภาษา" ซึ่งเป็นชุดของสตริง
jpalecek

27
จนถึงขณะนี้ยังไม่มีคำตอบที่ได้ให้คำจำกัดความของคุณว่า "ไวยากรณ์ที่ไม่มีบริบท" ในใจของฉันคำตอบที่ถูกต้องสำหรับคำถามนี้อาจอ้างอิงการผลิตในภาคผนวก A ที่ไม่ตรงกับคำจำกัดความของคุณหรือแสดงให้เห็นว่าคำนิยามของคุณไม่ถูกต้องหรือไม่เพียงพอ ยืนพื้นของคุณ!
การแข่งขัน Lightness ใน Orbit

8
ดูไวยากรณ์ของ D นั้นไร้บริบทจริงๆหรือ . ที่จริงแล้วฉันคิดว่าทุกคนที่นี่ควรอ่านคำถามและคำตอบของมัน!
การแข่งขัน Lightness ใน Orbit

คำตอบ:


341

ด้านล่างคือการสาธิตที่ชื่นชอบ (ปัจจุบัน) ของฉันว่าเหตุใดการแยก 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  ( |α|หมายถึง "ความยาวของα")

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


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

7
@mehrdad ผู้ใช้ OP กล่าวว่า "ภาษาที่คำนึงถึงบริบท" ไม่ใช่ไวยากรณ์ตามบริบท ความกำกวมเป็นคุณสมบัติของไวยากรณ์ไม่ใช่ภาษา แน่นอนว่าภาษานั้นไวต่อบริบท แต่ไม่ใช่เพราะไวยากรณ์ที่เฉพาะเจาะจงสำหรับภาษานั้นมีความคลุมเครือ
rici

2
โปรดทราบว่าตัวอย่างของฉันไม่ชัดเจน เป็นการแสดงออกที่ชัดเจนของโปรแกรมที่ถูกต้อง หากคุณเปลี่ยนค่าในบรรทัดที่ 21 ค่านั้นอาจเปลี่ยนรูปแบบไม่ได้ แต่ไม่ว่าในกรณีใดมันจะคลุมเครือ
rici

5
ฉันมีข้อสงสัยหนึ่งอย่าง: เมื่อคุณแสดงผลลัพธ์ของการประเมินเทมเพลตสามารถสร้างความแตกต่างระหว่างโปรแกรมที่มีรูปแบบดีและโปรแกรมที่มีรูปแบบไม่ดี การประเมินเทมเพลตนั้นทำให้สมบูรณ์ ดังนั้นจะไม่ถูกต้องพิจารณาว่าสตริงอยู่ในภาษา (C ++) ต้องทัวริงสมบูรณ์ ดังที่คุณพูดภาษาไวต่อบริบทคือ "เพียงแค่" ออโตเมติกที่มีขอบเขต จำกัด "ซึ่งไม่ใช่ AFAIK ที่สมบูรณ์แบบ หรืออาร์กิวเมนต์ของคุณใช้ขีด จำกัด มาตรฐาน C ++ ในบางสิ่งรวมถึงความลึกของการประเมินเทมเพลตหรือไม่

4
@AntonGolov: ตัวอย่างต้นฉบับของฉันทำแค่นั้น (คุณสามารถทำได้โดยการใส่0เข้าไปข้างใน()เพื่อให้ดูง่าย ๆ ) แต่ฉันคิดว่ามันน่าสนใจมากขึ้นด้วยวิธีนี้เพราะมันแสดงให้เห็นว่าคุณต้องการอินสแตนซ์ของแม่แบบ สตริงเป็นโปรแกรม C ++ ที่ถูกต้องทางไวยากรณ์ หากทั้งสองสาขารวบรวมกันฉันต้องทำงานหนักขึ้นเพื่อโต้แย้งการโต้แย้งว่าความแตกต่างคือ "ความหมาย" อยากรู้อยากเห็น แต่ฉันมักจะกำลังท้าทายในการกำหนด "ประโยค" ไม่มีใครได้เคยเสนอคำนิยามของ "ความหมาย" อื่น ๆ กว่า "สิ่งที่ผมไม่คิดว่าเป็นประโยค" :)
RICI

115

ก่อนอื่นคุณสังเกตอย่างถูกต้องว่าไม่มีกฎเกณฑ์ที่ไวต่อบริบทในไวยากรณ์ที่ท้ายมาตรฐาน C ++ ดังนั้นไวยากรณ์นั้นไม่มีบริบท

อย่างไรก็ตามไวยากรณ์นั้นไม่ได้อธิบายถึงภาษา C ++ อย่างแม่นยำเพราะมันสร้างโปรแกรมที่ไม่ใช่ C ++ เช่น

int m() { m++; }

หรือ

typedef static int int;

ภาษา C ++ ที่กำหนดเป็น "ชุดของโปรแกรม C ++ ที่มีรูปแบบที่ดี" นั้นไม่ได้มีบริบท (เป็นไปได้ที่จะแสดงให้เห็นว่าเพียงแค่เรียกร้องตัวแปรที่ต้องการประกาศเท่านั้นที่จะทำให้เป็นเช่นนั้น) เนื่องจากคุณสามารถเขียนโปรแกรมทัวริงที่สมบูรณ์ในทางทฤษฎีและสร้างโปรแกรมที่ไม่ถูกต้องตามผลลัพธ์ของมันจึงไม่ได้คำนึงถึงบริบท

ตอนนี้คนที่โง่เขลา (โดยทั่วไปไม่ใช่นักทฤษฎีภาษา แต่นักออกแบบคำแยกวิเคราะห์) มักใช้ "ไม่ใช้บริบท" ในความหมายต่อไปนี้

  • คลุมเครือ
  • ไม่สามารถแยกวิเคราะห์ด้วยวัวกระทิง
  • ไม่ใช่ LL (k), LR (k), LALR (k) หรือคลาสภาษาใด ๆ ที่กำหนดโดยโปรแกรมแยกวิเคราะห์

ไวยากรณ์ที่ด้านหลังของมาตรฐานไม่ตรงตามหมวดหมู่เหล่านี้ (นั่นคือไม่ชัดเจนไม่ใช่ LL (k) ... ) ดังนั้นไวยากรณ์ C ++ คือ "ไม่ใช้บริบท" สำหรับพวกเขา และในแง่หนึ่งพวกเขาพูดถูกมันยากมากที่จะผลิตตัวแยกวิเคราะห์ C ++ ที่ใช้งานได้

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


7
ambiguity doesn't have anything to do with context-sensitivityนี่คือสัญชาตญาณของฉันด้วยดังนั้นฉันดีใจที่เห็นคน (ก) เห็นด้วยและ (ข) อธิบายว่าฉันทำอะไรไม่ได้ ฉันเชื่อว่ามันตัดสิทธิ์ข้อโต้แย้งทั้งหมดที่มีพื้นฐานมาจากa b(c);และบางส่วนตอบสนองคำถามเดิมที่มีการอ้างว่า "ได้ยินบ่อยๆ" ของความไวต่อบริบทเนื่องจากความกำกวม ... โดยเฉพาะอย่างยิ่งเมื่อไวยากรณ์ไม่มีความคลุมเครือแม้แต่ใน MVP
Lightness Races ในวงโคจร

6
@KonradRudolph: สิ่งที่มาตรฐานกล่าวคือ "มีปริมาณที่กำหนดโดยการนำไปปฏิบัติซึ่งระบุขีด จำกัด ของความลึกทั้งหมดของอินสแตนซ์แบบเรียกซ้ำซึ่งอาจเกี่ยวข้องกับแม่แบบมากกว่าหนึ่งแบบผลลัพธ์ของการเรียกซ้ำแบบไม่มีที่สิ้นสุดในอินสแตนซ์ (14.7.1p15) ฉันตีความว่าหมายความว่าการนำไปปฏิบัติไม่จำเป็นต้องเข้าใจทุกโปรแกรม c ++ ที่ถูกต้องไม่ใช่โปรแกรมที่มีขนาดใหญ่เกินไประดับความลึกการเรียกซ้ำไม่ถูกต้อง คนเดียวที่ถูกทำเครื่องหมายว่าไม่ถูกต้องคือคนที่มีความลึกเรียกซ้ำไม่สิ้นสุด
rici

3
@ KonradRudolph: ฉันโต้แย้งว่ามันเป็น "การอ้างอิงทั่วไป" ความจริงที่ว่าฉันอ่านบทความที่ค่อนข้างซับซ้อนและไม่เข้าใจพอที่จะแยกแยะข้อเท็จจริงเล็ก ๆ น้อย ๆ นี้ควรจะเพียงพอที่จะแสดงให้เห็นว่า ไม่ใช่ว่าคุณพูดอะไรบางอย่างเช่น "คอมพิวเตอร์มักใช้ไฟฟ้า" หรือ "บิตอาจเป็นจริงหรือเท็จ"
Lightness Races ในวงโคจร

3
หากข้อเท็จจริงนี้เป็นที่รู้จักกันอย่างกว้างขวางจริง ๆ ฉันคิดว่ามันจะง่ายกว่าที่จะหาการอ้างอิงถึงมันมากกว่าที่จะเถียงในเรื่องที่เกี่ยวกับว่าควรให้ใคร ไม่ต้องพูดถึงที่สร้างสรรค์
ซามูเอลเอ็ดวินวอร์ด

5
เท่าที่ฉันสามารถบอกได้ @Konrad เข้าใจผิดเมื่อเขาพูดว่า "บริบทที่ไวต่อความรู้สึกเทียบเท่ากับทัวริงสมบูรณ์" (อย่างน้อยเขาก็คือถ้าเขาบอกว่า "นับซ้ำ" โดย "ทัวริงสมบูรณ์") และตั้งแต่นั้นมาก็ไม่สามารถรับรู้ข้อผิดพลาดนี้ นี่คือข้อมูลอ้างอิงสำหรับความสัมพันธ์แบบรวมกลุ่มที่เหมาะสมที่เกี่ยวข้องที่นี่: en.wikipedia.org/wiki/Chomsky_hierarchy
pnkfelix

61

ใช่. นิพจน์ต่อไปนี้มีลำดับของการดำเนินการที่แตกต่างกันขึ้นอยู่กับบริบทที่แก้ไขแล้ว :

แก้ไข: เมื่อลำดับการดำเนินการที่แท้จริงแตกต่างกันไปมันทำให้ยากอย่างเหลือเชื่อที่จะใช้คอมไพเลอร์ "ปกติ" ที่แยกวิเคราะห์ไปยัง AST ที่ไม่มีการตกแต่งก่อนที่จะทำการตกแต่ง (การเผยแพร่ข้อมูลประเภท) บริบทที่มีความอ่อนไหวตามบริบทอื่น ๆ ที่กล่าวถึงคือ "ค่อนข้างง่าย" เปรียบเทียบกับสิ่งนี้ (ไม่ใช่การประเมินเทมเพลตนั้นง่ายเลย)

#if FIRST_MEANING
   template<bool B>
   class foo
   { };
#else
   static const int foo = 0;
   static const int bar = 15;
#endif

ติดตามโดย:

static int foobar( foo < 2 ? 1 < 1 : 0 > & bar );

เหตุใดปัญหาดังกล่าวจึงไม่สามารถแก้ไขได้เช่นเดียวกับ C โดยการจำนิยามประเภทที่อยู่ในขอบเขต
Blaisorblade

1
@Blaisorblade: วิธีหนึ่งในการสร้างคอมไพเลอร์ "clean" คือการแยกงานออกเป็นขั้นตอนอิสระในห่วงโซ่เช่นการสร้างทรีแยกวิเคราะห์จากอินพุตตามด้วยขั้นตอนที่ทำการวิเคราะห์ประเภท C ++ บังคับให้คุณทำอย่างใดอย่างหนึ่ง 1) ผสานขั้นตอนเหล่านี้เป็นหนึ่งหรือ 2) แยกวิเคราะห์เอกสารตาม / การตีความทั้งหมดที่เป็นไปได้และอนุญาตให้ขั้นตอนการแก้ปัญหาประเภทพิมพ์แคบลงเพื่อการตีความที่ถูกต้อง
Sam Harwell

@ 280Z28: ตกลง แต่นั่นเป็นกรณีสำหรับ C เช่นกัน ฉันคิดว่าคำตอบที่ดีสำหรับคำถามนี้ควรแสดงว่าทำไม C ++ ถึงแย่กว่า C วิทยานิพนธ์ระดับปริญญาเอกที่เชื่อมโยงที่นี่ทำเช่นนี้: stackoverflow.com/a/243447/53974
Blaisorblade

26

ในการตอบคำถามของคุณคุณต้องแยกคำถามที่แตกต่างกันสองข้อ

  1. ไวยากรณ์เพียงเกือบทุกภาษาการเขียนโปรแกรมไม่ขึ้นกับบริบท โดยทั่วไปจะได้รับเป็นรูปแบบ Backus-Naur ที่ขยายออกหรือ gramar ที่ไม่มีบริบท

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

ในการสรุปว่า C ++ นั้นไม่มีบริบทหรือไม่นั้นขึ้นอยู่กับคำถามที่คุณถาม


5
เป็นที่น่าสนใจที่จะทราบว่าคุณมักจะต้องวางระดับ "เพียงไวยากรณ์" ต่ำกว่าที่คุณคาดหวังเพื่อให้ได้ CFG สำหรับภาษาการเขียนโปรแกรมของคุณ ยกตัวอย่างเช่น C คุณอาจคิดว่ากฎไวยากรณ์สำหรับการประกาศตัวแปรอย่างง่ายใน C จะเป็นVARDECL : TYPENAME IDENTIFIERแต่คุณไม่สามารถทำได้เพราะคุณไม่สามารถแยกชื่อประเภทจากตัวระบุอื่น ๆ ในระดับ CF อีกตัวอย่างหนึ่ง: ที่ระดับ CF คุณไม่สามารถตัดสินใจได้ว่าจะแยกวิเคราะห์a*bเป็นการประกาศตัวแปร ( bของตัวชี้ชนิดa) หรือเป็นการคูณ
LaC

2
@LaC: ใช่ขอบคุณที่ชี้ให้เห็น! โดยวิธีการที่ฉันแน่ใจว่ามีศัพท์เทคนิคที่ใช้กันอย่างแพร่หลายสำหรับไวยากรณ์เพียง ทุกคนมีคำที่ถูกต้องหรือไม่
ด่าน

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

13

คุณอาจต้องการดูการออกแบบและวิวัฒนาการของ C ++โดย Bjarne Stroustrup ในนั้นเขาอธิบายถึงปัญหาของเขาพยายามที่จะใช้ yacc (หรือคล้ายกัน) เพื่อแยกรุ่น C + + รุ่นแรกและต้องการให้เขาใช้เชื้อสายแบบเรียกซ้ำ


ว้าวขอบคุณ. ฉันสงสัยว่ามันสมเหตุสมผลหรือไม่ที่จะคิดว่าจะใช้สิ่งใดที่มีประสิทธิภาพมากกว่า CFG เพื่อแยกภาษาเทียมใด ๆ
Dervin Thunk

หนังสือที่ยอดเยี่ยมสำหรับการเข้าใจ whys ของ C ++ ฉันขอแนะนำและ Lippman's Inside C ++ Object Model เพื่อทำความเข้าใจว่า C ++ ทำงานอย่างไร แม้ว่าทั้งคู่จะเก่าไปนิด แต่พวกเขาก็ยังอ่านได้ดี
ราคาแมตต์

"Meta-S" เป็นเครื่องมือวิเคราะห์คำตามบริบทโดย Quinn Tyler Jackson ฉันไม่ได้ใช้มัน แต่เขาบอกเล่าเรื่องราวที่น่าประทับใจ ตรวจสอบความคิดเห็นของเขาใน comp.compilers และดูrnaparse.com/MetaS%20defined.htm
Ira Baxter

@IraBaxter: การอ้างอิง x ของคุณคือ MIA วันนี้ - และการอ้างอิงที่ชัดเจนเกี่ยวกับซอฟต์แวร์ดูเหมือนจะเข้าใจยาก (การค้นหาโดย Google ไม่มีโอกาสในการขายที่ดีใด ๆ ไม่ว่าจะด้วย 'site: rnaparse.com meta-s' หรือ 'quinn jackson meta- s '; มีบิตและชิ้นส่วน, แต่meta-s.comนำไปสู่เว็บไซต์ที่ไม่มีข้อมูล, เป็นต้น)
Jonathan Leffler

@ Jonathan: เดี๋ยวก่อนแค่สังเกตเห็นการร้องเรียนของคุณ Dunno ทำไมลิงค์ถึงไม่ดีฉันคิดว่ามันดีเมื่อฉันเขียนมัน Quinn เคยใช้งานได้ค่อนข้างสวยใน comp.compilers Google ดูเหมือนจะไม่เป็น ระเบียบนี่คือทั้งหมดที่ฉันสามารถหาได้: groups.google.com/group/comp.compilers/browse_thread/thread/th IIRC เขาลงนามในสิทธิ์ของ MetaS ให้กับเครื่องแต่งกายบางอย่างในฮาวายเพื่อทำการตลาดอีกครั้ง เมื่อพิจารณาว่าเรื่องนี้แปลกมากโดยเฉพาะ IMHO จึงได้ลงนามในใบสำคัญแสดงสิทธิการเสียชีวิต ฟังดูเหมือนเป็นโครงการที่ฉลาดมาก
Ira Baxter

12

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

ตัวอย่างแรก:

A*B;

นี่คือการแสดงออกการคูณหรือไม่?

หรือ

นี่เป็นการประกาศBตัวแปรที่จะเป็นตัวชี้ชนิดAหรือไม่?

หาก A เป็นตัวแปรแสดงว่าเป็นนิพจน์หากเป็นประเภทจะเป็นการประกาศตัวชี้

ตัวอย่างที่สอง:

A B(bar);

นี่เป็นฟังก์ชั่นต้นแบบที่ใช้อาร์กิวเมนต์barชนิดหรือไม่?

หรือ

นี่คือการประกาศตัวแปรBประเภทAและเรียกคอนสตรัคเตอร์ของ A ที่มีbarค่าคงที่เป็น initializer หรือไม่?

คุณต้องรู้อีกครั้งว่าbarเป็นตัวแปรหรือชนิดจากตารางสัญลักษณ์

ตัวอย่างที่สาม:

class Foo
{
public:
    void fn(){x*y;}
    int x, y;
};

นี่เป็นกรณีเมื่อการสร้างตารางสัญลักษณ์ในขณะที่การแยกวิเคราะห์ไม่ได้ช่วยเพราะการประกาศของ x และ y มาหลังจากนิยามฟังก์ชัน ดังนั้นคุณต้องสแกนผ่านคำจำกัดความของคลาสก่อนและดูที่นิยามของเมธอดในรอบที่สองเพื่อบอกว่า x * y เป็นนิพจน์ไม่ใช่การประกาศพอยน์เตอร์หรืออะไรก็ตาม


1
A B();เป็นการประกาศฟังก์ชันแม้ในนิยามฟังก์ชัน ค้นหาคำที่น่ารำคาญที่สุด ...
AProgrammer

"คุณไม่สามารถสร้างแผนผังไวยากรณ์โดยแยกวิเคราะห์ไฟล์" FALSE ดูคำตอบของฉัน
Ira Baxter

10

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

ดูสิ

ทำไม C ++ ไม่สามารถแยกวิเคราะห์ด้วยตัวแยกวิเคราะห์ LR (1)


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

int x;
x = 9 + 1.0;

คุณไม่สามารถอธิบายกฎต่อไปนี้ด้วยไวยากรณ์ที่ไม่มีบริบท: ด้านขวาของการกำหนดควรเป็นประเภทเดียวกันของด้านซ้ายมือ


4
ตัวแยกวิเคราะห์ C ++ ส่วนใหญ่ไม่ใช้เทคโนโลยีการแยกวิเคราะห์ GLR GCC ไม่ได้ บางคนทำ ดูsemanticdesigns.com/Products/FrontEnds/CppFrontEnd.htmlเพื่อดูสิ่งที่ทำ
Ira Baxter

10

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

นี้จะยังถามที่นี่: บริบทไวเทียบกับความคลุมเครือ

นี่คือไวยากรณ์ที่ไม่มีบริบท:

<a> ::= <b> | <c>
<b> ::= "x"
<c> ::= "x"

มันคลุมเครือดังนั้นเพื่อที่จะแยกวิเคราะห์อินพุต "x" คุณจำเป็นต้องมีบริบท (หรืออยู่กับความกำกวมหรือปล่อย "คำเตือน: E8271 - อินพุตมีความกำกวมในบรรทัดที่ 115") แต่แน่นอนว่าไม่ใช่ไวยากรณ์ที่ไวตามบริบท


การมีหลายสัญลักษณ์ทางซ้ายมือของการผลิตช่วยแก้ปัญหานี้ได้อย่างไร ฉันไม่คิดว่าคำตอบนี้กำลังตอบคำถาม
user541686

1
คำตอบของฉันคือการตอบสนองต่อประโยคแรก: "ฉันมักจะได้ยินคำกล่าวอ้างว่า C ++ เป็นภาษาที่คำนึงถึงบริบท" หากการกล่าวอ้างเหล่านั้นใช้นิพจน์ "แบบคำนึงถึงบริบท" อย่างไม่เป็นทางการแสดงว่าไม่มีปัญหา ฉันไม่คิดว่า C ++ มีความไวต่อบริบทอย่างเป็นทางการ
Omri Barel

ฉันคิดว่า C ++ มีความไวต่อบริบทอย่างเป็นทางการ แต่ปัญหาที่ฉันมีคือฉันไม่เข้าใจว่าไวยากรณ์ไวตามบริบทจะประสบความสำเร็จได้อย่างไรในการแยก C ++ มากกว่า CFG
541686

6

ไม่มีภาษาที่คล้ายกัน Algol ไม่มีบริบทเนื่องจากมีกฎที่ จำกัด นิพจน์และข้อความที่ตัวระบุสามารถปรากฏตามประเภทของพวกเขาและเนื่องจากไม่มีข้อ จำกัด เกี่ยวกับจำนวนข้อความที่สามารถเกิดขึ้นระหว่างการประกาศและการใช้งาน

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

C ++ ก้าวไปไกลกว่านี้ด้วยระบบเทมเพลตที่สมบูรณ์แบบของทัวริง ดูกองมากเกิน 794,015




5

มันไวต่อบริบทเช่นเดียวกับการa b(c);แยกวิเคราะห์และตัวแปรที่ถูกต้องสองรายการ เมื่อคุณพูดว่า "หากcเป็นประเภท" บริบทนั้นอยู่ตรงนั้นและคุณอธิบายได้อย่างชัดเจนว่า C ++ นั้นมีความละเอียดอ่อนอย่างไร หากคุณไม่มีบริบทของ "สิ่งที่c" คุณไม่สามารถแยกวิเคราะห์เรื่องนี้ได้อย่างชัดเจน

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

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


1
นอกจากนี้a<b<c>>dใช่มั้ย? (ตัวอย่างของคุณเป็นแบบคลาสสิกจากCซึ่งเป็นสิ่งกีดขวางเพียงอย่างเดียวที่ปราศจากบริบท)
Kerrek SB

ฉันคิดว่ามันเป็นปัญหาที่ทำให้งงมากกว่านี้ แต่แน่นอนในประเภทเดียวกันใช่
ลูกสุนัข

2
ถามไม่ได้ถามว่าเป็นมากขึ้นตามบริบทกว่า C เท่านั้นที่จะแสดงให้เห็นว่ามันเป็นไปตามบริบท
ลูกสุนัข

ดังนั้น .. คือ C ++ มากขึ้นตามบริบทกว่า C?
Kerrek SB

2
@DeadMG ฉันไม่คิดว่าคุณจะตอบคำถาม (ฉันไม่คิดว่าฉันเป็นอย่างนั้น) การมีเทอร์มินัลทางด้านซ้ายมือของการผลิตช่วยแก้ปัญหานี้ได้อย่างไร
user541686

5

การผลิตในมาตรฐาน C ++ นั้นปราศจากการเขียน แต่เราทุกคนรู้ว่าไม่ได้กำหนดภาษาอย่างแม่นยำ บางสิ่งที่คนส่วนใหญ่มองว่าเป็นความคลุมเครือในภาษาปัจจุบันสามารถ (ฉันเชื่อว่า) ได้รับการแก้ไขอย่างไม่น่าสงสัยกับไวยากรณ์ไวตามบริบท

int f(X);สำหรับตัวอย่างที่ชัดเจนที่สุดขอพิจารณารบกวนส่วนใหญ่แยกวิเคราะห์: ถ้าXเป็นค่าแล้วกำหนดนี้เป็นตัวแปรที่จะเริ่มต้นได้ด้วยf Xถ้าXเป็นประเภทมันจะนิยามfว่าเป็นฟังก์ชันที่ใช้พารามิเตอร์ชนิดXเดียว

เมื่อมองจากมุมมองทางไวยากรณ์เราสามารถดูได้ดังนี้:

A variable_decl ::= <type> <identifier> '(' initializer ')' ';'

B function_decl ::= <type> <identifier> '(' param_decl ')' ';'

A ::= [declaration of X as value]
B ::= [declaration of X as type]

แน่นอนว่าเพื่อให้ถูกต้องทั้งหมดเราจะต้องเพิ่ม "ข้อมูล" พิเศษบางอย่างลงในบัญชีสำหรับความเป็นไปได้ที่จะแทรกแซงการประกาศประเภทอื่น ๆ (เช่น A และ B ควรเป็นทั้ง "การประกาศรวมถึงการประกาศ X เป็น ... " หรือบางสิ่งในลำดับนั้น)

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

ด้วยเหตุนี้ฉันจึงต้องมองบางอย่างเพื่อให้แน่ใจ แต่ฉันเดาทันทีว่านี่ไม่ได้มีคุณสมบัติเป็น CSG อย่างน้อยที่สุดก็เป็นคำที่ใช้ตามปกติ


โปรดักชั่น (ที่ไม่มีบริบท) กำหนดการแยกวิเคราะห์ที่น่ารำคาญที่สุดได้ดีพอที่จะวิเคราะห์คำด้วยเอ็นจิ้นการแจงส่วนที่ไม่มีบริบท นั่นคือความล่าช้าของปัญหาในการตัดสินใจว่าการตีความหลายแบบนั้นถูกต้องจนกระทั่งหลังจากการแยกวิเคราะห์เสร็จสมบูรณ์ แต่เพียงทำให้วิศวกรรมของตัวแยกวิเคราะห์และตัวจำแนกชื่อง่ายขึ้น ดู AST สำหรับการแยกวิเคราะห์ที่ยุ่งยากที่สุด: stackoverflow.com/questions/17388771/…
Ira Baxter

5

กรณีที่ง่ายที่สุดของไวยากรณ์ที่ไม่มีบริบทเกี่ยวข้องกับการแยกวิเคราะห์นิพจน์ที่เกี่ยวข้องกับแม่แบบ

a<b<c>()

วิธีนี้สามารถแยกวิเคราะห์ได้เช่นกัน

template
   |
   a < expr > ()
        |
        <
      /   \
     b     c

หรือ

 expr
   |
   <
 /   \
a   template
     |
     b < expr > ()
          |
          c

AST สองตัวนั้นสามารถ disambiguated โดยการตรวจสอบการประกาศของ 'a' - AST เดิมหาก 'a' เป็นเทมเพลตหรืออันหลังถ้าไม่ใช่


ฉันเชื่อว่า C ++ 11 สั่งการตีความหลังและคุณต้องเพิ่ม parens เพื่อเลือกใช้กับอดีต
โจเซฟการ์วิน

1
@JosephGarvin ไม่ C ++ mandates ที่<จะต้องเป็นวงเล็บถ้ามันอาจจะเป็น (เช่นมันตามตัวบ่งชี้ที่ชื่อแม่แบบ) C ++ 11 เพิ่มข้อกำหนดที่>และอักขระตัวแรกของ>>ตีความเป็นวงเล็บปิดหากการใช้นั้นเป็นไปได้ นี้มีผลต่อการแยกของa<b>c>ที่aเป็นแม่แบบ a<b<c>แต่ไม่มีผลต่อ
rici

@aaron: มันง่ายกว่าa();(อย่างใดอย่างหนึ่งexpr.callหรือexpr.type.conv)
rici

@rici: โอ๊ะฉันไม่ทราบว่ามันไม่สมมาตร
Joseph Garvin

5
คุณกำลังอธิบายความคลุมเครือหรือความไวของบริบทหรือไม่
corazza

4

เทมเพลต C ++ แสดงให้เห็นว่าทัวริงทรงพลัง แม้ว่าจะไม่ใช่ข้อมูลอ้างอิงอย่างเป็นทางการ แต่นี่เป็นสถานที่ที่ควรพิจารณา:

http://cpptruths.blogspot.com/2005/11/c-templates-are-turing-complete.html

ฉันจะลองเดา (ตามหลักฐาน CACM ดั้งเดิมและแบบดั้งเดิมที่แสดงให้เห็นว่า ALGOL ในยุค 60 ไม่สามารถตอบโต้โดย CFG) และบอกว่า C ++ ไม่สามารถแยกวิเคราะห์ได้อย่างถูกต้องโดย CFG เท่านั้น CFGs ร่วมกับกลไก TP ต่าง ๆ ไม่ว่าจะเป็น tree pass หรือระหว่างการลดเหตุการณ์ - นี่เป็นอีกเรื่องหนึ่ง ในความหมายทั่วไปเนื่องจากปัญหาการหยุดทำงานมีบางโปรแกรม C ++ ที่ไม่สามารถแสดงให้เห็นว่าถูกต้อง / ไม่ถูกต้อง แต่ยังคงถูกต้อง / ไม่ถูกต้อง

{PS- ในฐานะผู้เขียน Meta-S (กล่าวถึงหลายคนข้างต้น) - ฉันสามารถพูดได้อย่างมั่นใจที่สุดว่า Thothic ไม่ได้หมดอายุและไม่มีซอฟต์แวร์ให้บริการฟรี บางทีฉันได้พูดคำตอบของฉันรุ่นนี้ว่าฉันจะไม่ถูกลบหรือลงคะแนนถึง -3.}


3

C ++ ไม่ใช่บริบท ฉันเรียนรู้เมื่อไม่นานมานี้ในการบรรยายคอมไพเลอร์ การค้นหาด่วนให้ลิงค์นี้โดยที่ส่วน "ไวยากรณ์หรือความหมาย" อธิบายว่าทำไม C และ C ++ ไม่บริบท:

Wikipedia Talk: ไวยากรณ์ที่ไม่มีบริบท

ขอแสดงความนับถือ
Ovanes


2

เห็นได้ชัดว่าถ้าคุณใช้คำต่อคำคำถามเกือบทุกภาษาที่มีตัวระบุจะคำนึงถึงบริบท

เราจำเป็นต้องรู้ว่าตัวระบุเป็นชื่อประเภท (ชื่อคลาส, ชื่อที่แนะนำโดย typedef, พารามิเตอร์เทมเพลต typename), ชื่อเทมเพลตหรือชื่ออื่น ๆ เพื่อให้สามารถใช้งานตัวระบุบางอย่างได้อย่างถูกต้อง ตัวอย่างเช่น

x = (name)(expression);

เป็นนักแสดงถ้าnameเป็นชื่อประเภทและการเรียกใช้ฟังก์ชั่นถ้าnameเป็นชื่อฟังก์ชั่น อีกกรณีหนึ่งคือสิ่งที่เรียกว่า "การแยกส่วนใหญ่ที่รบกวน" ซึ่งไม่สามารถแยกแยะคำจำกัดความของตัวแปรและการประกาศฟังก์ชันได้

ความยากลำบากนั้นได้แนะนำความต้องการtypenameและtemplateด้วยชื่อที่ต้องพึ่งพา ส่วนที่เหลือของ C ++ ไม่ไวต่อบริบทเท่าที่ฉันรู้ (เช่นเป็นไปได้ที่จะเขียนไวยกรณ์ตามบริบทสำหรับมัน)


2

Meta-S "เป็นเครื่องมือแยกวิเคราะห์ตามบริบทโดย Quinn Tyler Jackson ฉันไม่ได้ใช้ แต่เขาบอกเล่าเรื่องราวที่น่าประทับใจตรวจสอบความคิดเห็นของเขาใน comp.compilers และดู rnaparse.com/MetaS%20defined.htm - Ira Baxter 25 ก.ค. เวลา 10:42 น

ลิงก์ที่ถูกต้องคือการแยกวิเคราะห์ enigines

Meta-S เป็นทรัพย์สินของ บริษัท ที่ถูกเรียกว่า Thothic ฉันสามารถส่ง Meta-S ฟรีให้กับทุกคนที่สนใจและฉันใช้มันในการวิเคราะห์ rna แยกวิเคราะห์ โปรดทราบว่า "pseudoknot ไวยากรณ์" ที่รวมอยู่ในโฟลเดอร์ตัวอย่างถูกเขียนโดยนักชีวสารสนเทศศาสตร์โปรแกรมเมอร์มือสมัครเล่นและโดยทั่วไปจะไม่ทำงาน ไวยากรณ์ของฉันใช้แนวทางที่แตกต่างและทำงานได้ค่อนข้างดี


นี่คือการค้นหาที่น่าสนใจจริง ๆ
Dervin Thunk

0

ปัญหาใหญ่ที่นี่ก็คือคำว่า "ไม่มีบริบท" และ "คำนึงถึงบริบท" นั้นเป็นสิ่งที่ไม่เข้าใจง่ายในวิทยาศาสตร์คอมพิวเตอร์ สำหรับ C ++ ความไวตามบริบทดูเหมือนจะคลุมเครือ แต่ก็ไม่จำเป็นต้องเป็นจริงในกรณีทั่วไป

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

ตอนนี้ถ้าคำสั่งภายในฟังก์ชั่นร่างกายถูกแยกวิเคราะห์แตกต่างกันไปขึ้นอยู่กับสิ่งที่กำหนดไว้นอกบรรพบุรุษทางไวยากรณ์ทันที (เช่นว่าตัวระบุอธิบายประเภทหรือตัวแปร) เช่นในa * b;กรณีนั้นมันเป็นในความเป็นจริงตามบริบท ไม่มีความกำกวมที่แท้จริงที่นี่; มันจะถูกแยกวิเคราะห์เป็นประกาศของตัวชี้ถ้าaเป็นประเภทและการคูณเป็นอย่างอื่น

การคำนึงถึงบริบทนั้นไม่ได้หมายความว่า "ยากที่จะแยกวิเคราะห์" จริง ๆ แล้ว C นั้นไม่ยากเพราะa * b;"ความกำกวม" ที่น่าอับอายสามารถแก้ไขได้ด้วยตารางสัญลักษณ์ที่มีtypedefs พบก่อนหน้านี้ มันไม่จำเป็นต้องมีอินสแตนซ์ของแม่แบบโดยพลการใด ๆ (ซึ่งได้รับการพิสูจน์แล้วว่าเป็นทัวริงสมบูรณ์) เพื่อแก้ไขกรณีเช่น C ++ ในบางโอกาส จริงๆแล้วมันเป็นไปไม่ได้ที่จะเขียนโปรแกรม C ที่จะไม่คอมไพล์ในเวลา จำกัด แม้ว่ามันจะมีความไวต่อบริบทเดียวกันกับที่ C ++ ทำ

Python (และภาษาที่ไวต่อการเว้นวรรคอื่น ๆ ) ก็ขึ้นอยู่กับบริบทด้วยเนื่องจากต้องการสถานะใน lexer เพื่อสร้างโทเค็นการเยื้องและการอุทิศ แต่ไม่ได้ทำให้ยากในการแยกวิเคราะห์มากกว่าไวยากรณ์ LL-1 ทั่วไป มันใช้ parser-generator ซึ่งเป็นส่วนหนึ่งที่ทำให้ Python มีข้อความผิดพลาดทางไวยากรณ์ สิ่งสำคัญคือให้สังเกตที่นี่ว่าไม่มี "ความกำกวม" เหมือนa * b;ปัญหาใน Python ซึ่งเป็นตัวอย่างที่ดีของภาษาที่ไวต่อบริบทโดยไม่มีไวยากรณ์ "คลุมเครือ" (ดังที่กล่าวไว้ในวรรคแรก)


-4

คำตอบนี้บอกว่า C ++ ไม่ใช่บริบท ...มีความหมาย (ไม่ใช่โดยผู้ตอบ) ที่ไม่สามารถแยกวิเคราะห์ได้และคำตอบนำเสนอตัวอย่างรหัสที่ยากซึ่งสร้างโปรแกรม C ++ ที่ไม่ถูกต้องหากค่าคงที่บางอย่างไม่ใช่ จำนวนเฉพาะ.

ตามที่คนอื่น ๆ ได้สังเกตคำถามเกี่ยวกับว่าภาษานั้นไวต่อบริบทหรือไม่นั้นแตกต่างจากคำถามเดียวกันเกี่ยวกับไวยากรณ์ที่เฉพาะเจาะจงหรือไม่

ในการตั้งคำถามเกี่ยวกับการแยกวิเคราะห์ส่วนที่เหลือฉันเสนอหลักฐานเชิงประจักษ์ว่ามีไวยากรณ์แบบไม่มีบริบทสำหรับ C ++ ที่สามารถใช้ในการสร้าง AST สำหรับการแยกวิเคราะห์บริบทแบบไม่มีบริบทของข้อความต้นฉบับโดยการแยกวิเคราะห์ด้วย GLR ที่มีอยู่ -parser-based tool ที่ขับเคลื่อนด้วยไวยากรณ์ที่ชัดเจน

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

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

เครื่องมือนี้แก้ไขปัญหานี้ได้โดยแยกการแยกวิเคราะห์จากการตรวจสอบประเภทของโปรแกรมแยกวิเคราะห์ (ในกรณีที่มีการตีความหลายครั้งในกรณีที่ไม่มีบริบทจะบันทึกโหนดที่คลุมเครือในการแยกวิเคราะห์ที่มีการแยกวิเคราะห์ที่เป็นไปได้หลายประเภทการตรวจสอบประเภทจะตัดสินใจว่าอันใดถูกต้องและกำจัดทรีย่อยที่ไม่ถูกต้อง) คุณสามารถเห็นต้นไม้แยกวิเคราะห์ (บางส่วน) ในตัวอย่างด้านล่าง ต้นไม้ทั้งต้นมีขนาดใหญ่เกินไปที่จะพอดีกับคำตอบ SO หมายเหตุคุณจะได้รับการวิเคราะห์ต้นไม้ว่าจะใช้ค่า 234797 หรือ 234799 หรือไม่

การเรียกใช้เครื่องมือจำแนกชื่อ / ประเภทบน AST ด้วยค่าเดิม 234799 สำเร็จ ด้วยค่า 234797 ตัวจำแนกชื่อล้มเหลว (ตามที่คาดไว้) พร้อมกับข้อความแสดงข้อผิดพลาด "typen ไม่ใช่ประเภท" และเวอร์ชั่นนั้นไม่ใช่โปรแกรม C ++ ที่ถูกต้อง

967 tree nodes in tree.
15 ambiguity nodes in tree.
(translation_unit@Cpp~GCC5=2#6b11a20^0 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
 (declaration_seq@Cpp~GCC5=1021#6b06640^1#6b11a20:1 {10} Line 1 Column 1 File C:/temp/prime_with_templates.cpp
  (pp_declaration_seq@Cpp~GCC5=1022#6b049a0^1#6b06640:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   (declaration@Cpp~GCC5=1036#6b04980^1#6b049a0:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   |(template_declaration@Cpp~GCC5=2079#6b04960^1#6b04980:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   | (template_parameter_list@Cpp~GCC5=2082#6afbde0^1#6b04960:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |  (template_parameter@Cpp~GCC5=2085#6afbd80^1#6afbde0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   (parameter_declaration@Cpp~GCC5=1611#6afbd40^1#6afbd80:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6afb880^1#6afbd40:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6afb840^1#6afb880:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |  (trailing_type_specifier@Cpp~GCC5=1118#6afb7e0^1#6afb840:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   (simple_type_specifier@Cpp~GCC5=1138#6afb7a0^1#6afb7e0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |  )trailing_type_specifier#6afb7e0
   |   | )decl_specifier#6afb840
   |   |)basic_decl_specifier_seq#6afb880
   |   |(ptr_declarator@Cpp~GCC5=1417#6afbc40^1#6afbd40:2 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   | (noptr_declarator@Cpp~GCC5=1421#6afbba0^1#6afbc40:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |  (declarator_id@Cpp~GCC5=1487#6afbb80^1#6afbba0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   (id_expression@Cpp~GCC5=317#6afbaa0^1#6afbb80:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |(unqualified_id@Cpp~GCC5=319#6afb9c0^1#6afbaa0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6afb780^1#6afb9c0:1[`V'] Line 1 Column 15 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |)unqualified_id#6afb9c0
   |   |   )id_expression#6afbaa0
   |   |  )declarator_id#6afbb80
   |   | )noptr_declarator#6afbba0
   |   |)ptr_declarator#6afbc40
   |   )parameter_declaration#6afbd40
   |  )template_parameter#6afbd80
   | )template_parameter_list#6afbde0
   | (declaration@Cpp~GCC5=1033#6b04940^1#6b04960:2 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |  (block_declaration@Cpp~GCC5=1050#6b04920^1#6b04940:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   (simple_declaration@Cpp~GCC5=1060#6b04900^1#6b04920:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6b048e0^1#6b04900:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6b048c0^1#6b048e0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |  (type_specifier@Cpp~GCC5=1110#6b048a0^1#6b048c0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   (class_specifier@Cpp~GCC5=1761#6b04880^1#6b048a0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   |(class_head@Cpp~GCC5=1763#6afb980^1#6b04880:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   | (class_key@Cpp~GCC5=1791#6afbca0^1#6afb980:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp)class_key
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6afbcc0^1#6afb980:2[`answer'] Line 1 Column 25 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   | (optional_base_clause@Cpp~GCC5=1872#6afba60^1#6afb980:3 Line 1 Column 32 File C:/temp/prime_with_templates.cpp)optional_base_clause
   |   |   |)class_head#6afb980
   |   |   |(member_specification@Cpp~GCC5=1794#6b042e0^1#6b04880:2 {2} Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   | (member_declaration_or_access_specifier@Cpp~GCC5=1806#6b04060^1#6b042e0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |  (member_declaration@Cpp~GCC5=1822#6b04040^1#6b04060:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   (function_definition@Cpp~GCC5=1632#6b04020^1#6b04040:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |(function_head@Cpp~GCC5=1673#6afbec0^1#6b04020:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   | (ptr_declarator@Cpp~GCC5=1417#6afbfe0^1#6afbec0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (noptr_declarator@Cpp~GCC5=1422#6afbf80^1#6afbfe0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (noptr_declarator@Cpp~GCC5=1421#6afbf60^1#6afbf80:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(declarator_id@Cpp~GCC5=1487#6afbea0^1#6afbf60:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (id_expression@Cpp~GCC5=317#6afbb40^1#6afbea0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (unqualified_id@Cpp~GCC5=319#6afbc80^1#6afbb40:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6afbc20^1#6afbc80:1[`answer'] Line 1 Column 34 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   |   |  )unqualified_id#6afbc80
   |   |   |   |   | )id_expression#6afbb40
   |   |   |   |   |)declarator_id#6afbea0
   |   |   |   |   )noptr_declarator#6afbf60
   |   |   |   |   (parameter_declaration_clause@Cpp~GCC5=1559#6afbd00^1#6afbf80:2 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(pp_parameter_declaration_list@Cpp~GCC5=1570#6afb940^1#6afbd00:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (pp_parameter_declaration_seq@Cpp~GCC5=1574#6afb800^1#6afb940:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (parameter_declaration@Cpp~GCC5=1610#6afb9a0^1#6afb800:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (basic_decl_specifier_seq@Cpp~GCC5=1070#6afbf40^1#6afb9a0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(decl_specifier@Cpp~GCC5=1073#6afbfa0^1#6afbf40:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   | (trailing_type_specifier@Cpp~GCC5=1118#6afbfc0^1#6afbfa0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |  (simple_type_specifier@Cpp~GCC5=1140#6afb860^1#6afbfc0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |   |   |   | )trailing_type_specifier#6afbfc0
   |   |   |   |   |   |)decl_specifier#6afbfa0
   |   |   |   |   |   )basic_decl_specifier_seq#6afbf40
   |   |   |   |   |  )parameter_declaration#6afb9a0
   |   |   |   |   | )pp_parameter_declaration_seq#6afb800
   |   |   |   |   |)pp_parameter_declaration_list#6afb940
   |   |   |   |   )parameter_declaration_clause#6afbd00
   |   |   |   |   (function_qualifiers@Cpp~GCC5=1438#6afbce0^1#6afbf80:3 Line 1 Column 46 File C:/temp/prime_with_templates.cpp)function_qualifiers
   |   |   |   |  )noptr_declarator#6afbf80
   |   |   |   | )ptr_declarator#6afbfe0
   |   |   |   |)function_head#6afbec0
   |   |   |   |(function_body@Cpp~GCC5=1680#6b04000^1#6b04020:2 Line 1 Column 46 File C:/temp/prime_with_templates.cpp
   |   |   |   | (compound_statement@Cpp~GCC5=888#6afbee0^1#6b04000:1 Line 1 Column 46 File C:/temp/prime_with_templates.cpp)compound_statement
   |   |   |   |)function_body#6b04000
   |   |   |   )function_definition#6b04020
   |   |   |  )member_declaration#6b04040
   |   |   | )member_declaration_or_access_specifier#6b04060
   |   |   | (member_declaration_or_access_specifier@Cpp~GCC5=1806#6b042c0^1#6b042e0:2 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |  (member_declaration@Cpp~GCC5=1822#6b04820^1#6b042c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   (function_definition@Cpp~GCC5=1632#6b04280^1#6b04820:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |(function_head@Cpp~GCC5=1674#6b04220^1#6b04280:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b040e0^1#6b04220:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (decl_specifier@Cpp~GCC5=1073#6b040c0^1#6b040e0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (trailing_type_specifier@Cpp~GCC5=1118#6b040a0^1#6b040c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(simple_type_specifier@Cpp~GCC5=1138#6b04080^1#6b040a0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |   |   )trailing_type_specifier#6b040a0
   |   |   |   |  )decl_specifier#6b040c0
   |   |   |   | )basic_decl_specifier_seq#6b040e0
   |   |   |   | (ptr_declarator@Cpp~GCC5=1417#6b04200^1#6b04220:2 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (noptr_declarator@Cpp~GCC5=1422#6b041e0^1#6b04200:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (noptr_declarator@Cpp~GCC5=1421#6b041a0^1#6b041e0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(declarator_id@Cpp~GCC5=1487#6b04180^1#6b041a0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (id_expression@Cpp~GCC5=317#6b04160^1#6b04180:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (unqualified_id@Cpp~GCC5=320#6b04140^1#6b04160:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (operator_function_id@Cpp~GCC5=2027#6b04120^1#6b04140:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(operator@Cpp~GCC5=2070#6b04100^1#6b04120:1 Line 1 Column 62 File C:/temp/prime_with_templates.cpp)operator
   |   |   |   |   |   )operator_function_id#6b04120
   |   |   |   |   |  )unqualified_id#6b04140
   |   |   |   |   | )id_expression#6b04160
   |   |   |   |   |)declarator_id#6b04180
   |   |   |   |   )noptr_declarator#6b041a0
   |   |   |   |   (parameter_declaration_clause@Cpp~GCC5=1558#6afba40^1#6b041e0:2 Line 1 Column 65 File C:/temp/prime_with_templates.cpp)parameter_declaration_clause
   |   |   |   |   (function_qualifiers@Cpp~GCC5=1438#6b041c0^1#6b041e0:3 Line 1 Column 66 File C:/temp/prime_with_templates.cpp)function_qualifiers
   |   |   |   |  )noptr_declarator#6b041e0
   |   |   |   | )ptr_declarator#6b04200
   |   |   |   |)function_head#6b04220
   |   |   |   |(function_body@Cpp~GCC5=1680#6b04300^1#6b04280:2 Line 1 Column 66 File C:/temp/prime_with_templates.cpp
   |   |   |   | (compound_statement@Cpp~GCC5=889#6b04760^1#6b04300:1 Line 1 Column 66 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (pp_statement_seq@Cpp~GCC5=894#6b04780^1#6b04760:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (statement@Cpp~GCC5=857#6b04440^1#6b04780:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(jump_statement@Cpp~GCC5=1011#6afba80^1#6b04440:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (pm_expression@Cpp~GCC5=551#6b04380^1#6afba80:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (cast_expression@Cpp~GCC5=543#6b04360^1#6b04380:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (unary_expression@Cpp~GCC5=465#6b04340^1#6b04360:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(primary_expression@Cpp~GCC5=307#6b04320^1#6b04340:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   | (id_expression@Cpp~GCC5=317#6b042a0^1#6b04320:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |  (unqualified_id@Cpp~GCC5=319#6b04260^1#6b042a0:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6b04240^1#6b04260:1[`V'] Line 1 Column 74 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   |   |   |  )unqualified_id#6b04260
   |   |   |   |   |   | )id_expression#6b042a0
   |   |   |   |   |   |)primary_expression#6b04320
   |   |   |   |   |   )unary_expression#6b04340
   |   |   |   |   |  )cast_expression#6b04360
   |   |   |   |   | )pm_expression#6b04380
   |   |   |   |   |)jump_statement#6afba80
   |   |   |   |   )statement#6b04440
   |   |   |   |  )pp_statement_seq#6b04780
   |   |   |   | )compound_statement#6b04760
   |   |   |   |)function_body#6b04300
   |   |   |   )function_definition#6b04280
   |   |   |  )member_declaration#6b04820
   |   |   | )member_declaration_or_access_specifier#6b042c0
   |   |   |)member_specification#6b042e0
   |   |   )class_specifier#6b04880
   |   |  )type_specifier#6b048a0
   |   | )decl_specifier#6b048c0
   |   |)basic_decl_specifier_seq#6b048e0
   |   )simple_declaration#6b04900
   |  )block_declaration#6b04920
   | )declaration#6b04940
   |)template_declaration#6b04960
   )declaration#6b04980
  )pp_declaration_seq#6b049a0
  (pp_declaration_seq@Cpp~GCC5=1022#6b06620^1#6b06640:2 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   (declaration@Cpp~GCC5=1036#6b06600^1#6b06620:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   |(template_declaration@Cpp~GCC5=2079#6b065e0^1#6b06600:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   | (template_parameter_list@Cpp~GCC5=2083#6b05460^1#6b065e0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |  (template_parameter_list@Cpp~GCC5=2083#6b05140^1#6b05460:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   (template_parameter_list@Cpp~GCC5=2083#6b04ee0^1#6b05140:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |(template_parameter_list@Cpp~GCC5=2082#6b04cc0^1#6b04ee0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   | (template_parameter@Cpp~GCC5=2085#6b04ca0^1#6b04cc0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |  (parameter_declaration@Cpp~GCC5=1611#6b04c80^1#6b04ca0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04a40^1#6b04c80:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   |(decl_specifier@Cpp~GCC5=1073#6b04a20^1#6b04a40:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   | (trailing_type_specifier@Cpp~GCC5=1118#6b04a00^1#6b04a20:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   |  (simple_type_specifier@Cpp~GCC5=1138#6b049e0^1#6b04a00:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   | )trailing_type_specifier#6b04a00
   |   |   |)decl_specifier#6b04a20
   |   |   )basic_decl_specifier_seq#6b04a40
   |   |   (ptr_declarator@Cpp~GCC5=1417#6b04c40^1#6b04c80:2 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |(noptr_declarator@Cpp~GCC5=1421#6b04be0^1#6b04c40:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   | (declarator_id@Cpp~GCC5=1487#6b04bc0^1#6b04be0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |  (id_expression@Cpp~GCC5=317#6b04b60^1#6b04bc0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |   (unqualified_id@Cpp~GCC5=319#6b04ac0^1#6b04b60:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |   |(IDENTIFIER@Cpp~GCC5=3368#6b049c0^1#6b04ac0:1[`no'] Line 3 Column 15 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   )unqualified_id#6b04ac0
   |   |   |  )id_expression#6b04b60
   |   |   | )declarator_id#6b04bc0
   |   |   |)noptr_declarator#6b04be0
   |   |   )ptr_declarator#6b04c40
   |   |  )parameter_declaration#6b04c80
   |   | )template_parameter#6b04ca0
   |   |)template_parameter_list#6b04cc0
   |   |(template_parameter@Cpp~GCC5=2085#6b04ec0^1#6b04ee0:2 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   | (parameter_declaration@Cpp~GCC5=1611#6b04ea0^1#6b04ec0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |  (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04b40^1#6b04ea0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   (decl_specifier@Cpp~GCC5=1073#6b04ba0^1#6b04b40:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   |(trailing_type_specifier@Cpp~GCC5=1118#6b04c60^1#6b04ba0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   | (simple_type_specifier@Cpp~GCC5=1138#6b04580^1#6b04c60:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |)trailing_type_specifier#6b04c60
   |   |   )decl_specifier#6b04ba0
   |   |  )basic_decl_specifier_seq#6b04b40
   |   |  (ptr_declarator@Cpp~GCC5=1417#6b04e60^1#6b04ea0:2 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   (noptr_declarator@Cpp~GCC5=1421#6b04e40^1#6b04e60:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |(declarator_id@Cpp~GCC5=1487#6b04de0^1#6b04e40:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   | (id_expression@Cpp~GCC5=317#6b04d80^1#6b04de0:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |  (unqualified_id@Cpp~GCC5=319#6b04ce0^1#6b04d80:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6b04560^1#6b04ce0:1[`yes'] Line 3 Column 24 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |  )unqualified_id#6b04ce0
   |   |   | )id_expression#6b04d80
   |   |   |)declarator_id#6b04de0
   |   |   )noptr_declarator#6b04e40
   |   |  )ptr_declarator#6b04e60
   |   | )parameter_declaration#6b04ea0
   |   |)template_parameter#6b04ec0
   |   )template_parameter_list#6b04ee0
   |   (template_parameter@Cpp~GCC5=2085#6b05120^1#6b05140:2 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |(parameter_declaration@Cpp~GCC5=1611#6b05100^1#6b05120:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04d20^1#6b05100:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |  (decl_specifier@Cpp~GCC5=1073#6b04dc0^1#6b04d20:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |   (trailing_type_specifier@Cpp~GCC5=1118#6b04e80^1#6b04dc0:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |   |(simple_type_specifier@Cpp~GCC5=1140#6b046e0^1#6b04e80:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   )trailing_type_specifier#6b04e80
   |   |  )decl_specifier#6b04dc0
   |   | )basic_decl_specifier_seq#6b04d20
   |   | (ptr_declarator@Cpp~GCC5=1417#6b05080^1#6b05100:2 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |  (noptr_declarator@Cpp~GCC5=1421#6b05020^1#6b05080:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   (declarator_id@Cpp~GCC5=1487#6b05000^1#6b05020:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   |(id_expression@Cpp~GCC5=317#6b04fa0^1#6b05000:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   | (unqualified_id@Cpp~GCC5=319#6b04f00^1#6b04fa0:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   |  (IDENTIFIER@Cpp~GCC5=3368#6b046c0^1#6b04f00:1[`f'] Line 3 Column 33 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   | )unqualified_id#6b04f00
   |   |   |)id_expression#6b04fa0
   |   |   )declarator_id#6b05000
   |   |  )noptr_declarator#6b05020
   |   | )ptr_declarator#6b05080
   |   |)parameter_declaration#6b05100
   |   )template_parameter#6b05120
   |  )template_parameter_list#6b05140
   |  (template_parameter@Cpp~GCC5=2085#6b05440^1#6b05460:2 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   (parameter_declaration@Cpp~GCC5=1611#6b05420^1#6b05440:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6b05160^1#6b05420:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6b04fe0^1#6b05160:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |  (trailing_type_specifier@Cpp~GCC5=1118#6b050e0^1#6b04fe0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |   (simple_type_specifier@Cpp~GCC5=1140#6b050c0^1#6b050e0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |  )trailing_type_specifier#6b050e0
   |   | )decl_specifier#6b04fe0
   |   |)basic_decl_specifier_seq#6b05160
   |   |(ptr_declarator@Cpp~GCC5=1417#6b053e0^1#6b05420:2 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   | (noptr_declarator@Cpp~GCC5=1421#6b053c0^1#6b053e0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |  (declarator_id@Cpp~GCC5=1487#6b05360^1#6b053c0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   (id_expression@Cpp~GCC5=317#6b05280^1#6b05360:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   |(unqualified_id@Cpp~GCC5=319#6b051a0^1#6b05280:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6b046a0^1#6b051a0:1[`p'] Line 3 Column 40 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |)unqualified_id#6b051a0
   |   |   )id_expression#6b05280
   |   |  )declarator_id#6b05360
   |   | )noptr_declarator#6b053c0
   |   |)ptr_declarator#6b053e0
   |   )parameter_declaration#6b05420
   |  )template_parameter#6b05440
   | )template_parameter_list#6b05460

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

@Puppy: คุณสามารถพูดในสิ่งที่คุณชอบ แต่นั่นเป็นวิธีการทำงานของเครื่องมือ การลบชื่อเครื่องมือน่าจะทำให้ผู้คนถามว่าชื่อเครื่องมือคืออะไร
Ira Baxter

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