อ่านการประกาศตัวแปร C


41

พื้นหลัง

คำสั่งประกาศตัวแปรใน C ประกอบด้วยสามส่วนคือชื่อของตัวแปรมันพิมพ์ฐานและปรับปรุงประเภท (s)

การดัดแปลงประเภทมีสามประเภท:

  • ตัวชี้*(คำนำหน้า)
  • Array [N](postfix)
  • ฟังก์ชั่น()(postfix)
    • คุณสามารถระบุรายการอาร์กิวเมนต์ของฟังก์ชันภายใน parens แต่เพื่อความท้าทายนี้เราจะเพิกเฉยและลองใช้()(ซึ่งในทางเทคนิคหมายถึง "ฟังก์ชันสามารถใช้อาร์กิวเมนต์ชนิดใดก็ได้")

และวิธีในการอ่านเครื่องหมายเป็นดังนี้:

int i;             // i is an int
float *f;          // f is a pointer to a float
my_struct_t s[10]; // s is an array of 10 my_struct_t
int func();        // func is a function returning an int

สิ่งที่จับได้คือเราสามารถผสมสิ่งเหล่านี้เพื่อสร้างรูปแบบที่ซับซ้อนมากขึ้นเช่นอาร์เรย์ของอาร์เรย์หรืออาร์เรย์ของพอยน์เตอร์ของฟังก์ชันหรือตัวชี้ไปยังอาร์เรย์ของพอยน์เตอร์ :

int arr[3][4];
// arr is an array of 3 arrays of 4 ints

int (*fptrs[10])();
// fptrs is an array of 10 pointers to functions returning an int

float *(*p)[16];
// p is a pointer to an array of 16 pointers to float

ฉันอ่านข้อความที่ซับซ้อนเหล่านี้ได้อย่างไร

  1. เริ่มจากชื่อตัวแปร (name) is ...
  2. เลือกตัวดัดแปลงที่มีลำดับความสำคัญสูงสุด
  3. อ่านมัน:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. ทำซ้ำ 2 และ 3 จนกระทั่งโมดิฟายเออร์หมด
  5. ในที่สุดอ่านประเภทฐาน ... (base type).

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

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

int (*fptrs[10])();
      fptrs           fptrs is ...
           [10]       array of 10 ... // [] takes precedence over *
    (*         )      pointer to ...
                ()    function returning ...
int                   int

งาน

ให้บรรทัดของคำแถลงการประกาศตัวแปรที่เขียนใน C เอาท์พุทนิพจน์ภาษาอังกฤษที่อธิบายบรรทัดโดยใช้วิธีการที่แสดงด้านบน

อินพุต

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

  • [A-Za-z_][A-Za-z0-9_]*ทั้งพิมพ์ฐานและชื่อตัวแปรตรงกับการแสดงออกปกติ
  • ตามทฤษฎีแล้วโปรแกรมของคุณควรรองรับตัวดัดแปลงประเภทไม่ จำกัด จำนวน

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

  • ประเภทฐานอยู่เสมอคำเดียวเช่นint, float, ,uint32_t myStructบางอย่างเช่นunsigned long longจะไม่ถูกทดสอบ
  • สำหรับโน้ตอาร์เรย์[N]จำนวนNมักจะเป็นจำนวนเต็มบวกเดียวเขียนในฐาน 10. สิ่งที่ชอบint a[5+5], int a[SIZE]หรือint a[0x0f]จะไม่ได้รับการทดสอบ
  • สำหรับสัญกรณ์ฟังก์ชั่น()จะไม่มีการระบุพารามิเตอร์เลยตามที่กล่าวไว้ข้างต้น
  • สำหรับช่องว่าง0x20จะใช้อักขระช่องว่างเท่านั้น คุณสามารถ จำกัด โปรแกรมของคุณเฉพาะการใช้งานช่องว่างเช่น
    • ใช้เพียงหนึ่งช่องว่างหลังจากประเภทฐาน
    • ใช้ช่องว่างทุกที่ระหว่างโทเค็น
  • อย่างไรก็ตามคุณไม่สามารถใช้ช่องว่างต่อเนื่องตั้งแต่สองจุดขึ้นไปเพื่อถ่ายทอดข้อมูลมากกว่าการเป็นตัวคั่นโทเค็น

ตามไวยากรณ์ C ชุดค่าผสมสามชุดต่อไปนี้ไม่ถูกต้องและจะไม่ถูกทดสอบ:

  • f()() ฟังก์ชันส่งคืนฟังก์ชัน
  • f()[] ฟังก์ชันส่งคืนอาร์เรย์
  • a[]() ฟังก์ชัน Array of N

นักพัฒนา C ใช้แบบฟอร์มที่เทียบเท่าเหล่านี้แทน (และสิ่งเหล่านี้ครอบคลุมในกรณีทดสอบ):

  • (*f())()ฟังก์ชันส่งคืนตัวชี้ไปยังฟังก์ชัน
  • *f()ฟังก์ชันส่งกลับตัวชี้ไปที่องค์ประกอบแรกของอาร์เรย์
  • (*a[])()Array of N พอยน์เตอร์ที่ใช้งานได้

เอาท์พุต

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

อีกครั้งนี่คือกระบวนการแปลง:

  1. เริ่มจากชื่อตัวแปร (name) is ...
  2. เลือกตัวดัดแปลงที่มีลำดับความสำคัญสูงสุด
  3. อ่านมัน:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. ทำซ้ำ 2 และ 3 จนกระทั่งโมดิฟายเออร์หมด
  5. ในที่สุดอ่านประเภทฐาน ... (base type).

กรณีทดสอบ

int i;              // i is int
float *f;           // f is pointer to float
my_struct_t s[10];  // s is array of 10 my_struct_t
int func();         // func is function returning int
int arr[3][4];      // arr is array of 3 array of 4 int
int (*fptrs[10])(); // fptrs is array of 10 pointer to function returning int
float *(*p)[16];    // p is pointer to array of 16 pointer to float

_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];
/* _WTH_is_TH15 is pointer to function returning pointer to pointer to array of
   1234 array of 567 _RANdom_TYPE_123 */

uint32_t **(*(**(*(***p)[2])())[123])[4][5];
/* p is pointer to pointer to pointer to array of 2 pointer to function returning
   pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to
   pointer to uint32_t */

uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);
// Same as above, just more redundant parens

some_type (*(*(*(*(*curried_func())())())())())();
/* curried_func is function returning pointer to function returning pointer to
   function returning pointer to function returning pointer to
   function returning pointer to function returning some_type */

เกณฑ์การให้คะแนนและการชนะ

นี่คือความท้าทายโปรแกรมที่มีจำนวนไบต์น้อยที่สุดจะเป็นผู้ชนะ


9
ที่เกี่ยวข้อง: cdecl.org
user202729

int arr[3][4];คือan array of 3 arrays of 4 ints(ตามที่คุณพูด) หรือan array of 4 arrays of 3 ints?
Charlie

1
@ Charlie อดีตถูกต้อง sizeof(arr[0]) == sizeof(int[4])ดังนั้นรายการของarrประกอบด้วยสี่ints
Bubbler

1
อินพุตมี;จุดสิ้นสุดของบรรทัดหรือไม่?
Black Owl Kai

2
@ KamilDrakari มันเป็นเรื่องหลัง "array of pointer to function" เป็นหลัก "array of pointer" ซึ่งใช้ได้อย่างสมบูรณ์ใน C.
Bubbler

คำตอบ:


17

Python 3 , 331 312 294 261 240 ไบต์

from re import*
class V(str):__pos__=lambda s:V(s+'pointer to ');__call__=lambda s:V(s+'function returning ');__getitem__=lambda s,i:V(s+'array of %i '%i)
t,e=input().split()
print(eval(sub('\*','+',sub('(\w+)',r'V("\1 is ")',e[:-1],1)))+t)

ลองออนไลน์!

-19 ไบต์โดยเปลี่ยนไปใช้ python 2 และใส่คำจำกัดความของคลาสลงใน exec

-18 ไบต์โดยเปลี่ยน regex จาก[a-zA-Z_][a-zA-Z0-9_]*เป็น\\w+ขอบคุณ Kevin Cruijssen

-33 ไบต์โดยใช้เวทย์มนตร์คำจำกัดความของคลาสและใช้ประโยชน์ str ขอบคุณลินน์เปลี่ยนกลับเป็นไพ ธ อน 3

-21 ไบต์โดยรวมหลาย ๆ regexes เข้าด้วยกันขอบคุณ infmagic2047

ต้องการให้มีช่องว่างหนึ่งช่องเท่านั้นที่มีอยู่ในอินพุต (ระหว่างประเภทและนิพจน์)

ฉันคิดว่านี่เป็นวิธีที่ไม่ซ้ำกันในการแก้ปัญหา สิ่งนี้ส่วนใหญ่ใช้ความจริงที่ว่า Python สามารถประเมินสตริงเช่น(**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])และรับลำดับการเรียกใช้ฟังก์ชันดัชนีอาเรย์และพอยน์เตอร์ที่ถูกต้องและผู้ใช้สามารถโอเวอร์โหลดสิ่งเหล่านี้ได้


1
เป็นวิธีที่ดี +1 จากฉัน! คุณสามารถกอล์ฟ[a-zA-Z_][A-Za-z0-9_]*ที่จะ[a-zA-Z_]\\w*บันทึกไม่กี่ไบต์ แก้ไข: อันที่จริงผมคิดว่าคุณก็สามารถใช้แทน\\w+ [a-zA-Z_][A-Za-z0-9_]*
Kevin Cruijssen

ฉันชอบวิธีนี้ :) นี่มันมีขนาด 253 ไบต์
Lynn

1
นั่นเป็นจุดที่ดี 261เป็นแล้ว
ลินน์

1
คุณสามารถใช้[0]แทน.group()ตั้งแต่ Python 3.6
infmagic2047

1
และนี่เป็นรุ่น 240 ไบต์
infmagic2047

13

เรติน่า 0.8.2 , 142 138 128 117 ไบต์

(\w+) (.+);
($2) $1
\(\)
 function returning
\[(\d+)?]
 array of$#1$* $1
+`\((\**)(.+)\)
$2$1
\*
 pointer to
1` 
 is 

ลองออนไลน์! ลิงค์มีกรณีทดสอบ ไวยากรณ์ที่ดีขึ้น แก้ไข: บันทึก10 21 bytes โดยการแก้ปัญหา Pip ของ @ DLosc คำอธิบาย:

(\w+) (.+);
($2) $1

ย้ายประเภทที่จะสิ้นสุดและตัดส่วนที่เหลือของการประกาศในที่ในกรณีที่มันมีด้านนอก()*

\(\)
 function returning

ประมวลผลฟังก์ชั่นใด ๆ

\[(\d+)?]
 array of$#1$* $1

ประมวลผลอาร์เรย์ใด ๆ

+`\((\**)(.+)\)
$2$1

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

\*
 pointer to

ประมวลผลพอยน์เตอร์ใด ๆ

1` 
 is 

isใส่


7

Java 11, 469 467 463 450 ไบต์

s->{String r="",t,S[];for(s=s.replace("()","~");s.contains("(");s=s.replace(t,"").replace("()",""),r+=t+";")t=s.replaceAll(".*(\\([^()]+\\)).*","$1");S=s.split(" ");t=S[0];r+=r.isEmpty()?S[1]:s;S=r.split(";");r=S[0].replaceAll(".*?(\\w+).*","$1 is ");for(var p:S)r+=p.replaceAll("[A-Za-z_]+\\d+|[^\\[\\d]","").replaceAll("\\[(\\d+)","array of $1 ")+(p.contains("~")?"function returning ":"")+"pointer to ".repeat(p.split("\\*").length-1);return r+t;}

ลองออนไลน์

คำอธิบาย:

s->{               // Method with String as both parameter and return-type
  String r="",     //  Result-String, starting empty
         t,        //  Temp-String, starting uninitialized
         S[];      //  Temp String-array, starting uninitialized
  for(s=s.replace("()","~");
                   //  Replace all "()" in the input `s` with "~"
      s.contains("(");
                   //  Loop as long as the input `s` still contains "("
      ;            //    After every iteration:
       s=s.replace(t,"")
                   //     Remove `t` from `s`
          .replace("()",""),
                   //     And also remove any redundant parenthesis groups
       r+=t+";")   //     Append `t` and a semi-colon to the result-String
    t=s.replaceAll(".*(\\([^()]+\\)).*","$1");
                   //   Set `t` to the inner-most group within parenthesis
  S=s.split(" ");  //  After the loop, split the remainder of `s` on the space
  t=S[0];          //  Set `t` to the first item (the type)
  r+=              //  Append the result-String with:
    r.isEmpty()?   //   If the result-String is empty
                   //   (so there were no parenthesis groups)
     S[1]          //    Set the result-String to the second item
    :              //   Else:
     s;            //    Simple append the remainder of `s`
  S=r.split(";");  //  Then split `r` on semi-colons
  r=S[0].replaceAll(".*?(\\w+).*",
                   //  Extract the variable name from the first item
     "$1 is ");    //  And set `r` to this name appended with " is "
  for(var p:S)     //  Loop over the parts split by semi-colons:
    r+=            //   Append the result-String with:
      p.replaceAll("[A-Za-z_]+\\d+
                   //    First remove the variable name (may contain digits)
         |[^\\[\\d]","")
                   //    And then keep only digits and "["
       .replaceAll("\\[(\\d+)",
                   //    Extract the number after "["
         "array of $1 ")
                   //    And append the result-String with "array of " and this nr
      +(p.contains("~")?
                   //    If the part contains "~"
         "function returning "
                   //     Append the result-String with "function returning "
       :           //    Else:
        "")        //     Leave the result-String the same
      +"pointer to ".repeat(
                   //    And append "pointer to " repeated
         p.split("\\*").length-1);
                   //    the amount of "*" in the part amount of time
  return r         //  Then return the result-String
          +t;}     //  appended with the temp-String (type)

ล้มเหลวในกรณีทดสอบที่มีวงเล็บที่ซ้ำซ้อน
Bubbler

@Bubler Ah ไม่ได้สังเกตว่ากรณีทดสอบใหม่ โชคดีที่มันเป็นเรื่องง่าย
Kevin Cruijssen

6

Bash + cdecl + GNU sed, 180

cdeclเป็นยูทิลิตี Unix ที่น่าเชื่อถือซึ่งทำสิ่งที่จำเป็นส่วนใหญ่ที่นี่ แต่เพื่อให้ตรงกับข้อกำหนดของ I / O sedจำเป็นต้องมีการประมวลผลก่อนและหลังการประมวลผลบางอย่าง:

sed -r 's/^/explain struct /;s/struct (int|char double|float|void) /\1 /;s/\bfunc/_func/g'|cdecl|sed -r 's/^declare //;s/as/is/;s/struct //g;s/([0-9]+) of/of \1/g;s/\b_func/func/g'
  • ไม่มีความพยายามแก้ไขไวยากรณ์

sed การประมวลผลล่วงหน้า:

  • s/^/explain struct /- เพิ่ม "อธิบาย struct" ไปยังจุดเริ่มต้นของทุกบรรทัด
  • s/struct (int|char double|float|void) /\1 /- ลบออกstructเมื่อจัดการกับประเภทภาษา C
  • s/\bfunc/_func/g - "func" ได้รับการยอมรับว่าเป็นคำหลักโดย cdecl - ยับยั้งสิ่งนี้

sed การประมวลผลภายหลัง:

  • s/^declare // - ลบ "ประกาศ" ที่จุดเริ่มต้นของบรรทัด
  • s/as/is/ - อธิบายตนเอง
  • s/struct //g - ลบคำหลัก "struct" ทั้งหมด
  • s/([0-9]+) of/of \1/g - ลำดับที่ถูกต้องของ "ของ"
  • s/\b_func/func/g - ย้อนกลับ "_func" ใด ๆ ที่ถูกแทนที่ในการประมวลผลล่วงหน้า

ในการดำเนินการ:

$ < cdecls.txt sed -r 's/^/explain struct /;s/struct (int|char double|float|void) /\1 /;s/\bfunc/_func/g'|cdecl|sed -r 's/^declare //;s/as/is/;s/struct //g;s/([0-9]+) of/of \1/g;s/\b_func/func/g'
i is int
f is pointer to float
s is array of 10 my_struct_t
func is function returning int
arr is array of 3 array of 4 int
fptrs is array of 10 pointer to function returning int
p is pointer to array of 16 pointer to float
_WTH_is_TH15 is pointer to function returning pointer to pointer to array of 1234 array of 567 _RANdom_TYPE_123
p is pointer to pointer to pointer to array of 2 pointer to function returning pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to pointer to uint32_t
p is pointer to pointer to pointer to array of 2 pointer to function returning pointer to pointer to array of 123 pointer to array of 4 array of 5 pointer to pointer to uint32_t
curried_func is function returning pointer to function returning pointer to function returning pointer to function returning pointer to function returning pointer to function returning some_type
$ 

มันจะเพียงพอที่จะทำs/\bfu/_fu/gและบันทึกไบต์ของการfuncแทนที่แบบเต็ม?
DLosc

รอมันเป็นสาธารณูปโภคจริงหรือ ฉันคิดเสมอว่ามันเป็นชื่อของเว็บไซต์
phuclv

@phuclv cdecl เป็นโปรแกรมอรรถประโยชน์และมีประโยชน์มากสำหรับการตรวจสอบการประกาศ C
Patricia Shanahan


ล้มเหลวในการตั้งชื่อตัวแปรas(+4 ไบต์สำหรับช่องว่างที่จะแก้ไข) ฉันไม่ได้มีการเข้าถึงcdeclแต่ฉันคิดว่าคุณสามารถบันทึก 64 sed -r 's/^(\w+)(\W+)/explain struct \1_\2_/'|cdecl|sed -r 's/^declare struct _|_$//;s/ as / is /;s/([0-9]+) of/of \1/g'ไบต์ใช้
Neil

6

พิพ -s , 152 150 148 139 137 126 125 123 ไบต์

แนวทางที่สาม!

YaRs" ("R';')R`\[(\d+)]`` array of \1`R"()"" function returning"L#aYyR`\((\**)(.+)\)`{c." pointer to"X#b}{[b"is"g@>2a]}Vy^s

รับการประกาศเป็นอินพุตบรรทัดคำสั่ง ลองออนไลน์!

คำอธิบาย

รหัสอยู่ในสามส่วน: การตั้งค่าเริ่มต้นและการจัดการฟังก์ชั่นและอาร์เรย์; ลูปที่จัดการกับวงเล็บและพอยน์เตอร์ และการจัดเรียงครั้งสุดท้าย

ตั้งค่าฟังก์ชั่นและอาร์เรย์

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

Y                         Yank into y variable...
 a                        The result of a (the cmdline arg)...
  R s                     Replace the space
   " ("                    with " ("
  R ';                    Replace the semicolon
   ')                      with a closing paren
  R `\[(\d+)]`            Replace digits in square brackets
   ` array of \1`          with " array of <digits>"
  R "()"                  Replace function parens
   " function returning"   with " function returning"

ถ้าใส่เดิมของเราคือตอนนี้เรามีfloat *((*p()))[16];float (*((*p function returning)) array of 16)

วงเล็บและตัวชี้

เราเรียกใช้ลูปแทนที่วงเล็บคู่นอกสุดสุดและเครื่องหมายดอกจันใด ๆ ที่อยู่ในวงเล็บเปิดทันที

L#a                   Loop len(a) times (enough to complete all replacements):
 Y                    Yank into y variable...
  y                   The result of y...
   R `\((\**)(.+)\)`  Replace open paren, 0 or more asterisks (group 1), 1 or more
                      characters (group 2), and close paren
    {                  with this callback function (b = group 1, c = group 2):
     c .               The stuff in the middle, concatenated to...
      " pointer to"    that string
       X #b            repeated len(asterisks) times
    }

ขั้นตอนตัวอย่าง:

float (*((*p function returning)) array of 16)
float ((*p function returning)) array of 16 pointer to
float (*p function returning) array of 16 pointer to
float p function returning pointer to array of 16 pointer to

ทำความสะอาด

สิ่งเดียวที่เหลืออยู่คือการย้ายประเภทไปยังจุดสิ้นสุดและเพิ่ม "คือ":

{[b"is"g@>2a]}Vy^s
               y^s  Split y on spaces
{            }V     Use the resulting list as arguments to this function:
 [          ]        Return a list of:
  b                   2nd argument (the variable name)
   "is"               That string
       g@>2           All arguments after the 2nd
           a          1st argument (the type)
                    The resulting list is printed, joining on spaces (-s flag)

สำหรับคำนิยามเช่นint x;นี้วิธีการนี้จะส่งผลให้มีพื้นที่เพิ่มเติมซึ่งได้รับอนุญาตจากการท้าทาย


5

JavaScript (ES6), 316 ... 268 253 ไบต์

s=>(g=s=>[/\d+(?=])/,/\*/,/!/,/.+ /,/\w+/].some((r,i)=>(S=s.replace(r,s=>(O=[O+`array of ${s} `,O+'pointer to ','function returning '+O,O+s,s+' is '+O][i],'')))!=s)?g(S):'',F=s=>(O='',S=s.replace(/\(([^()]*)\)/,g))!=s?O+F(S):g(s)+O)(s.split`()`.join`!`)

ลองออนไลน์!

แสดงความคิดเห็น

ฟังก์ชั่นผู้ช่วย

g = s =>                             // s = expression to parse
  [                                  // look for the following patterns in s:
    /\d+(?=])/,                      //   array
    /\*/,                            //   pointer
    /!/,                             //   function
    /.+ /,                           //   type
    /\w+/                            //   variable name
  ].some((r, i) =>                   // for each pattern r at index i:
    ( S = s.replace(                 //   S = new string obtained by removing
      r,                             //       the pattern matching r from s
      s => (                         //     using the first match s and the index i,
        O = [                        //     update the output O:
          O + `array of ${s} `,      //       array
          O + 'pointer to ',         //       pointer
          'function returning ' + O, //       function
          O + s,                     //       type
          s + ' is ' + O             //       variable name
        ][i],                        //
        ''                           //     replace the match with an empty string
    )))                              //   end of replace()
    != s                             //   make some() succeed if S is not equal to s
  ) ?                                // end of some(); if truthy:
    g(S)                             //   do a recursive call with S
  :                                  // else:
    ''                               //   stop recursion and return an empty string

ส่วนสำคัญ

s => (                 // s = input
  g = …,               // define the helper function g (see above)
  F = s => (           // F = recursive function, taking a string s
    O = '',            //   O = iteration output, initialized to an empty string
    S = s.replace(     //   S = new string obtained by removing the next expression from s
      /\(([^()]*)\)/,  //     look for the deepest expression within parentheses
      g                //     and process it with the helper function g
    )                  //   end of replace()
  ) != s ?             // if S is not equal to s:
    O + F(S)           //   append O to the final output and do a recursive call with S
  :                    // else (we didn't find an expression within parentheses):
    g(s) + O           //   process the remaining expression with g and return O
)(s.split`()`.join`!`) // initial call to F with all strings '()' in s replaced with '!'

ผมก็สงสัยว่าทำไมคุณใช้[...s.split`()`.join`!`]แทนเพียง[...s.replace('()','!')]แต่ฉันรู้ว่ามันเป็นที่แน่นอนเดียวกันไบต์นับ .. :)
เควิน Cruijssen

@KevinCruijssen เหตุผลหลักคือs.replace('()','!')จะแทนที่เหตุการณ์แรกเท่านั้น
Arnauld

อ่าแน่นอน ลืม JS แทนที่ไม่เหมือนกับของ Java ใน Java .replaceจะแทนที่สิ่งที่เกิดขึ้นทั้งหมดและ.replaceAllแทนที่สิ่งที่เกิดขึ้นทั้งหมดเมื่อเปิดใช้งาน regex มักจะคิดว่าการตั้งชื่อก็ค่อนข้างน้อยมากสำหรับทั้งสองวิธีใน Java เท่าที่ผมจะเรียกว่าพวกเขา.replaceAllและ.regexReplaceAllหรือสิ่งที่ตามเส้นเหล่านั้น แต่ผมคิดว่าสำหรับ codegolf มันสั้นลงและ.replace .replaceAll
Kevin Cruijssen

1
BTW ฉันสังเกตเห็นว่าคุณกำลังใช้เทคนิคเดียวกัน (พร้อม~) หลังจากโพสต์คำตอบของฉันในเวอร์ชันแรก จิตใจที่ยิ่งใหญ่คิดเหมือนกันฉันคิดว่า : p
Arnauld

3

ทำความสะอาด 415 ไบต์

import StdEnv,Text
$s#(b,[_:d])=span((<>)' ')(init s)
=join" "(?d++[""<+b])
?[]=[]
?['()':s]=["function returning": ?s]
?['*':s]= ?s++["pointer to"]
?['[':s]#(n,[_:t])=span((<>)']')s
=["array of "<+n: ?t]
?s=case@0s of(['(':h],t)= ?(init h)++ ?t;(h,t)|t>[]= ?h++ ?t=[h<+" is"]
~c=app2((++)[c],id)
@n[c:s]=case c of'('= ~c(@(n+1)s);')'|n>1= ~c(@(n-1)s)=([c],s);_|n>0= ~c(@n s)=span(\c=c<>'('&&c<>'[')[c:s]
@_ e=(e,e)

ลองออนไลน์!


3

R , 225 218 ไบต์

g=gsub
"&"="@"=paste
"["=function(a,b)a&"array of"&b
"+"=function(a)a&"pointer to"
eval(parse(t=g('\\(\\)','@"function returning"',g('(\\w+) (.*?)([A-Za-z_]\\w*)(.*);','\\2"\\3 is"\\4&"\\1"',g('\\*','+',readline())))))

ลองออนไลน์!

โปรแกรมเต็มรูปแบบพร้อมฟังก์ชั่นการทำงานบน TIO เพื่อการทดสอบที่สะดวกในกรณีทดสอบทั้งหมดในครั้งเดียว

แรกเราจะใช้ Regex การแปลงใส่ของรูปแบบการtype ...name...; ..."name is"..."type"สัญกรณ์ฟังก์ชั่น()จะถูกแปลงเป็นข้อความด้วยตัวดำเนินการเรียงต่อกันที่มีลำดับความสำคัญสูง น่าเสียดายที่เราต้องแทนที่*ด้วย+เนื่องจากอดีตไม่เป็นที่ยอมรับในฐานะผู้ประกอบการเอก ส่วนที่เหลือทำโดย R's evalพร้อมตัวดำเนินการที่โอเวอร์โหลด


1
ทางออกที่ฉลาด!
J.Doe

3

Perl 6 , 209 190 171 162 153 ไบต์

{~({(.[1]Z'is'),.<e>.&?BLOCK,('array of'X .[2]),('function returning','pointer to'Zxx.[3,0])if $_}(m:g/(\*)*[(\w+)+|\(<e=~~>.][\[(\d+).]*(\(.)*/[1]),$0)}

ลองออนไลน์!

วิธีการ regex แบบเรียกซ้ำ ผลิตอักขระช่องว่างบางพิเศษซึ่งสามารถหลีกเลี่ยงค่าใช้จ่ายของ 3 ไบต์

คำอธิบาย

{     # Anonymous block
 ~(   # Convert list to string
   {  # Block converting a regex match to a nested list
     (.[1]            # Array of 0 or 1 variable names
       Z'is'),        # zipped with string "is"
     .<e>.&?BLOCK,    # Recursive call to block with subexpression
     ('array of'      # String "array of"
       X .[2]),       # prepended to each array size
     ('function returning',  # Strings "function returning"
      'pointer to'           # and "pointer to"
      Zxx             # zipped repetition with
      .[3,0])         # number of function and pointer matches
     if $_            # Only if there's an argument
   }
   (             # Call block
     m:g/        # Input matched against regex
      (\*)*      # Sequence of asterisks, stored in [0]
      [          # Either
       (\w+)+    # the variable name, stored as 1-element array in [1]
       |         # or
       \(        # literal (
         <e=~~>  # the same regex matched recursively, stored in <e>
       .         # )
      ]
      [\[(\d+).]*  # Sequence of "[n]" with sizes stored in [2]
      (\(.)*       # Sequence of "()" stored in [3]
     /
     [1]  # Second match
   ),
   $0     # First match (base type)
 )
}

2

JavaScript 250 ไบต์ [249?]

สิ่งนี้ใช้ 250 ไบต์:

k=>(a=k.match(/\W|\w+/g),s=[v=j=r=""],f=y=>!j&!a[i+1]||(m=a[i],v?(r+=v=m=='['?`array of ${a[i+=3,i-2]} `:m<')'?(i+=2,"function returning "):s[j-1]=='*'?j--&&"pointer to ":""):m==')'?v=j--|i++:m<'+'?s[j++]=a[i++]:r+=a[v=i++]+" is ",f(),r+a[0]),f(i=2))

คำอธิบาย:

โดยทั่วไปจะอ่านจากบัฟเฟอร์aซึ่งเป็นอินพุตโทเค็น มันจะย้ายโทเค็นจากบัฟเฟอร์aไปยังสแต็กอย่างต่อเนื่องsจนกว่าจะมีการเรียกใช้โหมดการประเมินผล โหมดการประเมินผลการดำเนินงานจะใช้ postfix แรก(), []จากบัฟเฟอร์และจากนั้นก็จะใช้ประกอบการคำนำหน้า*จากสแต็ค โหมดการประเมินผลจะถูกเรียกใช้เมื่อสถานะเป็นที่ที่คำจะเป็น (ทั้งชื่อและที่อยู่ถูกค้นพบและบริโภคหรือสิ้นสุด)และพบและลบออก) โหมดการประเมินถูกปิดใช้งานเมื่อไม่พบตัวดำเนินการส่วนนำหน้า / หลังคำเพิ่มเติม

k=>( // k is input
    a=k.match(/\W|\w+/g), // split by symbol or word
    s=[v=j=r=""], // j=0, v=false, r="", s=[]
    // s is the stack, r is the return string,
    // v is true if we're in evaluation mode (Consume (), [], *)
    // v is false if we're waiting to see a ) or token, which triggers evaluation
    // j is the index of the top of the stack (Stack pointer)
    f=y=>!j&!a[i+1]||( // !j means stack is empty, !a[i+1] means we're at the ;
        m=a[i], // Save a[i] in a variable
        v // Are we evaluating?
        ?(
        r+=v=
            m=='[' // Array
            ?`array of ${a[i+=3,i-2]} ` // Skip three tokens: "[", "10", "]"
                                        // a[i-2] is the "10"
            :m<')' // m == '('
                ?(i+=2,"function returning ") // Skip two tokens: "(", ")"
                :s[j-1]=='*' // Stack has a pointer
                    ?j--&&"pointer to " // Pop the stack
                    :"" // Set v to be false, r+=""
        )
        :m==')'
            ?v=j--|i++ // Pop the '(', skip over the ')', v = Evaluation mode
            :m<'+' // m == '*' || m == '('
                ?s[j++]=a[i++] // push(s, pop(a))
                :r+=a[v=i++]+" is " // Otherwise we have the token
        , f(), r+a[0] // Recurse f(), and return r+a[0]. a[0] is the type.
    ),
    f(i=2) // Set i=2, and call f(), which returns the final value r + type
    // a = ["type", " ", ...], so i=2 give the first real token
    // This soln assumes there is only one space, which is an allowed assumption
)

บันทึก

ถ้าฉันเข้าใจ "ใช้ช่องว่างทุกที่ระหว่างโทเค็น" อย่างถูกต้อง:

k=>(a=k.split(" "),s=[v=j=r=""],f=y=>!j&!a[i+1]||(v?(r+=v=a[i]=='['?`array of ${a[i+=3,i-2]} `:a[i]<')'?(i+=2,"function returning "):s[j-1]=='*'?j--&&"pointer to ":""):a[i]==')'?v=j--|i++:a[i]<'+'?s[j++]=a[i++]:r+=a[v=i++]+" is ",f(),r+a[0]),f(i=1))

ถูกต้องทางเทคนิคและการใช้งาน

249 ไบต์

สมมติว่ามีช่องว่างระหว่างโทเค็นทุกอัน


2
ฉันใช้เวลาหลายชั่วโมงแม้จะดูตรงไปตรงมาก็ตาม ฉันอาจจะเคาะ 5-10 ไบต์ / ชั่วโมงเริ่มต้นด้วย 350 ตัวอักษร แน่นอนฉันไม่มีชีวิต
Nicholas Pipitone

2
ผมอยู่ที่ประมาณ 325 เมื่อฉันคิดว่า "ฉันตี optimality กับขั้นตอนวิธีการปัจจุบันของฉัน - ฉีก" แต่แล้วด้วยเหตุผลบางอย่างผมก็ยังไม่สามารถที่จะเคาะ 5-10 / ชั่วโมงแม้จะเคาะแต่ละถูกตามด้วย "เอาล่ะนี่คือแน่นอนผลลัพธ์ที่ดีที่สุด " การกดปุ่ม 250 นั้นเป็นกฎเกณฑ์เนื่องจากเป็นคนแรกที่เอาชนะการครองราชย์ 253 ดังนั้นแม้ว่าฉันจะยังพูดว่า "โอเคนี่เป็นผลลัพธ์ที่ดีที่สุดอย่างแน่นอน " แต่อาจมีการเพิ่มประสิทธิภาพมากกว่านี้
Nicholas Pipitone

1

สีแดง , 418 410 ไบต์

func[s][n: t:""a: charset[#"a"-#"z"#"A"-#"Z"#"0"-#"9""_"]parse s[remove[copy x thru" "(t: x)]to a
change[copy x[any a](n: x)]"#"]b: copy[]until[c: next find s"#"switch c/1[#"("[append
b"function returning"take/part c 2]#"["[parse c[remove[skip copy d to"]"(append b
reduce["array of"d])skip]]]#")"#";"[take c c: back back c while[#"*"= c/1][take c
c: back c append b"pointer to"]take c]]s =""]reduce[n"is"b t]]

ลองออนไลน์!

คำอธิบาย:

f: func [ s ] [
    n: t: 0                                         ; n is the name, t is the type
    a: charset [ #"a"-#"z" #"A"-#"Z" #"0"-#"9" "_" ]; characters set for parsing 
    parse s[                                        ; parse the input with the following rules
        remove [ copy x thru " " ](t: x)            ; find the type, save it to t and remove it from the string
        to a                                        ; skip to the next alphanumerical symbol
        change [ copy n [ any a ] (n: x) ] "#"      ; save it to n and replace it with '#'
    ]
    b: copy [ ]                                     ; block for the modifiers 
    until [                                         ; repeat 
       c: next find s "#"                           ; find the place of the name   
       switch c/1 [                                 ; and check what is the next symbol
           #"(" [ append b "function returning"     ; if it's a '('- it's a function - add the modifier       
                  take/part c 2                     ; and drop the "()"
                ]
           #"[" [ parse c [                         ; '[' - an array
                     remove [ skip copy d to "]"    ; save the number
                             (append b reduce [     ; and add the modifier 
                                  "array of" d
                              ] )                   
                             skip ]                 ; and remove it from the string
                     ]
                ]
           #")"                                     ; a closing bracket 
           #";" [ take c                            ; or ';' - drop it
                    c: back back c                  ; go to the left 
                    while [ #"*" = c/1 ]            ; and while there are '*'
                    [
                        take c                      ; drop them
                        c: back c                   ; go to the left
                        append b "pointer to"       ; add the modifier
                    ]
                    take c                          ; drop '(' (or space)
                 ]
       ]
       s = ""                                       ; until the string is exhausted
    ]
    reduce [ n "is" b t ]                     ; display the resul
]

0

APL (NARS), ตัวอักษร 625, ไบต์ 1250

CH←⎕D,⎕A,⎕a,'_'⋄tkn←nm←∆←''⋄in←⍬⋄⍙←lmt←lin←0
eb←{∊(1(0 1 0)(0 1)(1 0))[⍺⍺¨⍵]}
tb←{x←({⍵='[':3⋄⍵=']':4⋄⍵∊CH,' ':1⋄2}eb⍵)\⍵⋄(x≠' ')⊂x}

gt
tkn←''⋄→0×⍳⍙>lin⋄tkn←∊⍙⊃in⋄⍙+←1⋄→0×⍳(⍙>lin)∨'('≠↑tkn⋄→0×⍳')'≠↑⍙⊃in⋄tkn←tkn,⍙⊃in⋄⍙+←1

r←dcl;n
   n←0
B: gt⋄→D×⍳'*'≠↑tkn⋄n+←1⋄→B×⍳tkn≢''
D: r←ddcl⋄∆←∆,∊n⍴⊂'pointer to '

r←ddcl;q
   r←¯1⋄→0×⍳0>lmt-←1
   →A×⍳∼'('=↑tkn⋄q←dcl⋄→F×⍳')'=↑tkn⋄→0
A: →B×⍳∼(↑tkn)∊CH⋄nm←tkn⋄→F
B: r←¯2⋄→0
F: gt⋄→G×⍳∼tkn≡'()'⋄∆←∆,'function that return '⋄→F
G: →Z×⍳∼'['=↑tkn⋄∆←∆,'array of ',{''≡p←(¯1↓1↓tkn):''⋄p,' '}⋄→F
Z: r←0

r←f w;q
   nm←∆←''⋄in←tb w⋄⍙←1⋄lin←↑⍴in⋄lmt←150⋄gt⋄→A×⍳∼0>q←dcl⋄r←⍕q⋄→0
A: r←nm,' is a ',∆,1⊃in

นี่เป็นแค่การแปลจากภาษา C ถึง APL จากโค้ดในหนังสือ: "Linguaggio C" โดย Brian W. Kerninghan และ Dennis M. Ritchie ตอนที่ 5.12 ฉันไม่ทราบว่าจะลดทั้งหมดได้อย่างไรเพราะฉันไม่เข้าใจรหัสนั้น 100% และเนื่องจากฉันไม่รู้จัก APL มากเกินไป ... ฟังก์ชั่นสำหรับการออกกำลังกายคือ f; ฉันคิดว่าได้รับอนุญาตเพียง 150 พาเรนต์ซ้อนกัน '(' ')' สำหรับข้อผิดพลาดส่งคืนหนึ่ง strign ที่มีค่าลบหนึ่งค่าในนั้นหรือการสืบทอดสตริงหากทั้งหมดตกลง ดูเหมือนว่านี่จะไม่ดีกว่าเวอร์ชันอื่นแม้ว่าจะมีตัวอักษรน้อยลงเพราะอีกตัวหนึ่งเห็นข้อผิดพลาดดีกว่า การทดสอบบางอย่าง:

  f 'int f()()'
f is a function that return function that return int
  f 'int a[]()'
a is a array of function that return int
  f 'int f()[]'
f is a function that return array of int
  f 'int i;'
i is a int
  f 'float *f;'
f is a pointer to float
  f 'my_struct_t s[10];'
s is a array of 10 my_struct_t
  f 'int func();'
func is a function that return int
  f 'int arr[3][4];'
arr is a array of 3 array of 4 int
  f 'int (*fptrs[10])();'
fptrs is a array of 10 pointer to function that return int
  f 'float *(*p)[16]; '
p is a pointer to array of 16 pointer to float
  f '_RANdom_TYPE_123 (**(*_WTH_is_TH15)())[1234][567];'
_WTH_is_TH15 is a pointer to function that return pointer to pointe
  r to array of 1234 array of 567 _RANdom_TYPE_123
  f 'uint32_t (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5]);'
p is a pointer to pointer to pointer to array of 2 pointer to funct
  ion that return pointer to pointer to array of 123 pointer to
   array of 4 array of 5 pointer to pointer to uint32_t
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.