Đọc khai báo biến C


41

Lý lịch

Câu lệnh khai báo biến trong C bao gồm ba phần: tên của biến, kiểu cơ sở của nó và (các) biến tố loại .

Có ba loại sửa đổi loại:

  • Con trỏ *(tiền tố)
  • Mảng [N](hậu tố)
  • Hàm ()(hậu tố)
    • Bạn có thể chỉ định một danh sách các đối số hàm bên trong parens, nhưng vì lợi ích của thách thức này, chúng ta hãy bỏ qua nó và chỉ sử dụng ()(về mặt kỹ thuật có nghĩa là "hàm có thể lấy bất kỳ loại đối số nào").

Và một cách để đọc các ký hiệu như sau:

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

Điều hấp dẫn là chúng ta có thể trộn tất cả những thứ này để tạo thành một loại phức tạp hơn, chẳng hạn như mảng mảng hoặc mảng con trỏ hàm hoặc con trỏ tới mảng con trỏ :

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

Làm thế nào tôi đọc những tuyên bố phức tạp này?

  1. Bắt đầu từ tên biến. (name) is ...
  2. Chọn công cụ sửa đổi có quyền ưu tiên cao nhất.
  3. Đọc nó:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Lặp lại 2 và 3 cho đến khi hết sửa đổi.
  5. Cuối cùng, đọc loại cơ sở. ... (base type).

Trong C, các toán tử postfix được ưu tiên hơn các toán tử tiền tố và các biến tố loại không phải là ngoại lệ. Do đó, []()ràng buộc đầu tiên, sau đó *. Bất cứ điều gì bên trong một cặp parens (...)(không bị nhầm lẫn với toán tử hàm) liên kết đầu tiên trên bất kỳ thứ gì bên ngoài.

Ví dụ minh họa:

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

Bài tập, nhiệm vụ

Đưa ra một dòng câu lệnh khai báo biến được viết bằng C, xuất ra biểu thức tiếng Anh mô tả dòng đó, sử dụng phương thức hiển thị ở trên.

Đầu vào

Đầu vào là một câu lệnh C duy nhất bao gồm một loại cơ sở duy nhất, một tên biến duy nhất, các biến tố loại 0 hoặc nhiều hơn và dấu chấm phẩy kết thúc. Bạn phải thực hiện tất cả các yếu tố cú pháp được đề cập ở trên, cộng với:

  • Cả loại cơ sở và tên biến đều khớp với biểu thức chính quy [A-Za-z_][A-Za-z0-9_]*.
  • Về mặt lý thuyết, chương trình của bạn nên hỗ trợ số lượng sửa đổi loại không giới hạn.

Bạn có thể đơn giản hóa các yếu tố cú pháp C khác theo các cách sau (triển khai đầy đủ cũng được hoan nghênh):

  • Các loại cơ sở luôn luôn là một từ duy nhất, ví dụ như int, float, uint32_t, myStruct. Một cái gì đó giống như unsigned long longsẽ không được thử nghiệm.
  • Đối với các ký hiệu mảng [N], số lượng Nsẽ luôn luôn là một số nguyên dương đơn bằng văn bản trong cơ sở 10. Những điều như int a[5+5], int a[SIZE]hoặc int a[0x0f]sẽ không được kiểm tra.
  • Đối với ký hiệu hàm (), không có tham số nào được chỉ định cả, như đã chỉ ra ở trên.
  • Đối với khoảng trắng, chỉ ký tự khoảng trắng 0x20sẽ được sử dụng. Bạn có thể giới hạn chương trình của mình để sử dụng cụ thể các khoảng trắng, ví dụ:
    • Chỉ sử dụng một khoảng trắng sau loại cơ sở
    • Sử dụng khoảng trắng ở mọi nơi giữa các mã thông báo
  • Tuy nhiên, bạn không thể sử dụng hai hoặc nhiều khoảng trắng liên tiếp để truyền tải nhiều thông tin hơn là dấu tách mã thông báo.

Theo cú pháp C, ba kết hợp sau không hợp lệ và do đó sẽ không được kiểm tra:

  • f()() Chức năng trả về
  • f()[] Hàm trả về mảng
  • a[]() Mảng hàm N

Các nhà phát triển C sử dụng các hình thức tương đương này thay thế (và tất cả các hình thức này được đề cập trong các trường hợp thử nghiệm):

  • (*f())()Hàm trả về con trỏ cho hàm
  • *f()Hàm trả về con trỏ đến phần tử đầu tiên của mảng
  • (*a[])()Mảng con trỏ N hoạt động

Đầu ra

Đầu ra là một câu tiếng Anh. Bạn không cần (nhưng bạn có thể nếu bạn muốn) tôn trọng ngữ pháp tiếng Anh, ví dụ: việc sử dụng các a, an, thedạng số ít / số nhiều và dấu chấm kết thúc (dấu chấm). Mỗi từ nên được phân tách bằng một hoặc nhiều khoảng trắng (dấu cách, tab, dòng mới) để kết quả có thể đọc được.

Một lần nữa, đây là quá trình chuyển đổi:

  1. Bắt đầu từ tên biến. (name) is ...
  2. Chọn công cụ sửa đổi có quyền ưu tiên cao nhất.
  3. Đọc nó:
    • * -> pointer to ...
    • [N] -> array of N ...
    • () -> function returning ...
  4. Lặp lại 2 và 3 cho đến khi hết sửa đổi.
  5. Cuối cùng, đọc loại cơ sở. ... (base type).

Các trường hợp thử nghiệm

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 */

Tiêu chí chấm điểm & chiến thắng

Đây là một thách thức . Chương trình có số byte nhỏ nhất sẽ thắng.


9
Liên quan: cdecl.org
user202729

int arr[3][4];an array of 3 arrays of 4 ints(như bạn nói), hay an array of 4 arrays of 3 ints?
Charlie

1
@Charlie Cái trước là đúng. sizeof(arr[0]) == sizeof(int[4]), vì vậy một mục arrchứa bốn ints.
Bong bóng

1
Đầu vào có chứa ;ở cuối dòng không?
Black Owl Kai

2
@KamilDrakari Đó là cái sau. "mảng con trỏ tới chức năng" thực chất là "mảng con trỏ", hoàn toàn hợp lệ trong C.
Bubbler

Câu trả lời:


17

Python 3 , 331 312 294 261 240 byte

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)

Hãy thử trực tuyến!

-19 byte bằng cách chuyển sang python 2 và đặt định nghĩa lớp vào một exec

-18 byte bằng cách thay đổi regex từ [a-zA-Z_][a-zA-Z0-9_]*sang \\w+, nhờ Kevin Cruijssen

-33 byte bằng cách thực hiện một số phép thuật định nghĩa lớp và sử dụng str, nhờ Lynn, đổi lại thành python 3

-21 byte bằng cách hợp nhất nhiều regex với nhau, nhờ infmagic2047

Yêu cầu chỉ có một khoảng trắng được chứa trong đầu vào (giữa kiểu và biểu thức).

Tôi nghĩ rằng đây là một cách tiếp cận khá độc đáo cho vấn đề. Điều này chủ yếu sử dụng thực tế là bản thân Python có thể đánh giá các chuỗi như (**((*(**(((*(((**(*p)))[2]))())))[123])[4])[5])và nhận được chuỗi lệnh gọi hàm, chỉ mục mảng và con trỏ chính xác - và người dùng có thể quá tải các chuỗi này.


1
Cách tiếp cận tốt đẹp, +1 từ tôi! Bạn có thể chơi golf [a-zA-Z_][A-Za-z0-9_]*để [a-zA-Z_]\\w*tiết kiệm một vài byte. EDIT: Thật ra, tôi nghĩ bạn chỉ có thể sử dụng \\w+thay vì [a-zA-Z_][A-Za-z0-9_]*.
Kevin Cruijssen

Tôi thích cách tiếp cận này :) ở đây là trong byte byte
Lynn

1
Đó là một điểm hay. 261 rồi.
Lynn

1
Bạn có thể sử dụng [0]thay vì .group()kể từ Python 3.6.
infmagic2047


13

Võng mạc 0.8.2 , 142 138 128 117 byte

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

Hãy thử trực tuyến! Liên kết bao gồm các trường hợp thử nghiệm. Ngữ pháp tốt hơn . Chỉnh sửa: Đã lưu 10 21 byte bằng cách chuyển giải pháp Pip của DLosc. Giải trình:

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

Di chuyển loại đến cuối và bọc phần còn lại của khai báo ()trong trường hợp nó chứa bên ngoài *.

\(\)
 function returning

Xử lý bất kỳ chức năng.

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

Xử lý bất kỳ mảng nào.

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

Di chuyển bất kỳ con trỏ nào đến cuối dấu ngoặc của chúng và xóa dấu ngoặc, làm việc liên tục từ bộ dấu ngoặc ngoài cùng vào trong.

\*
 pointer to

Xử lý bất kỳ con trỏ.

1` 
 is 

Chèn is.


7

Java 11, 469 467 463 450 byte

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;}

Hãy thử trực tuyến.

Giải trình:

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)

Thất bại trong trường hợp thử nghiệm với dấu ngoặc đơn thừa.
Bong bóng

@Bubbler Ah, không nhận thấy trường hợp thử nghiệm mới. May mắn thay, đó là một sửa chữa dễ dàng.
Kevin Cruijssen

6

Bash + cdecl + GNU sed, 180

cdecllà một tiện ích Unix đáng kính, thực hiện hầu hết những gì được yêu cầu ở đây, nhưng để phù hợp với các yêu cầu I / O, một số sedxử lý trước và sau xử lý là bắt buộc:

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'
  • Không có nỗ lực để thực hiện đúng ngữ pháp.

sed Tiền xử lý:

  • s/^/explain struct /- Thêm "giải thích struct" vào đầu mỗi dòng
  • s/struct (int|char double|float|void) /\1 /- Xóa structkhi giao dịch với các loại ngôn ngữ C
  • s/\bfunc/_func/g - "func" được nhận dạng là một từ khóa của cdecl - loại bỏ điều này

sed Hậu xử lý:

  • s/^declare // - xóa "khai báo" ở đầu dòng
  • s/as/is/ - tự giải thích
  • s/struct //g - xóa tất cả các từ khóa "struct"
  • s/([0-9]+) of/of \1/g - thứ tự đúng của "của"
  • s/\b_func/func/g - hoàn nguyên bất kỳ "_func" nào đã được thay thế trong quá trình tiền xử lý

Trong hành động:

$ < 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
$ 

Nó sẽ là đủ để làm s/\bfu/_fu/gvà lưu các byte của sự functhay thế đầy đủ ?
DLosc

chờ đợi nó là một tiện ích thực sự? Tôi đã luôn nghĩ rằng đó là tên của trang web
phuclv

@phuclv cdecl là một tiện ích thực sự và thực sự hữu ích để kiểm tra khai báo C.
Patricia Shanahan


Thất bại cho một biến có tên as(+4 byte cho khoảng trắng cần sửa). Tôi không có quyền truy cập cdeclnhưng tôi nghĩ bạn có thể lưu 64 byte bằng cách sử dụng 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

Pip -s , 152 150 148 139 137 126 125 123 byte

Cách tiếp cận thứ ba!

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

Lấy khai báo làm đầu vào dòng lệnh. Hãy thử trực tuyến!

Giải trình

Mã này gồm ba phần: thiết lập ban đầu và xử lý các hàm và mảng; một vòng lặp xử lý dấu ngoặc đơn và con trỏ; và một sự sắp xếp lại cuối cùng.

Thiết lập, chức năng và mảng

Chúng tôi muốn toàn bộ khai báo được ngoặc đơn (điều này giúp với vòng lặp sau này), vì vậy chúng tôi thay đổi type ...;thành type (...). Sau đó, quan sát rằng không có sự sắp xếp lại nào được thực hiện với các mô tả về hàm và mảng, vì vậy chúng ta có thể thực hiện tất cả các thay thế đó trước mà không ảnh hưởng đến đầu ra cuối cùng.

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"

Nếu đầu vào ban đầu của chúng tôi là float *((*p()))[16];, bây giờ chúng tôi có float (*((*p function returning)) array of 16).

Dấu ngoặc đơn và con trỏ

Chúng tôi chạy một vòng lặp thay thế cặp dấu ngoặc ngoài cùng và bất kỳ dấu sao nào ngay bên trong paren mở.

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
    }

Các bước ví dụ:

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

Dọn dẹp

Điều duy nhất còn lại là di chuyển loại đến cuối và thêm "là":

{[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)

Đối với các định nghĩa như int x;, cách tiếp cận này sẽ dẫn đến một không gian thêm, được cho phép bởi thách thức.


5

JavaScript (ES6), 316 ... 268 253 byte

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`!`)

Hãy thử trực tuyến!

Đã bình luận

Chức năng trợ giúp

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

Phần chính

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 '!'

Tôi đã tự hỏi tại sao bạn sử dụng [...s.split`()`.join`!`]thay vì chỉ [...s.replace('()','!')], nhưng tôi nhận ra đó chính xác là số byte tương tự .. :)
Kevin Cruijssen

@KevinCruijssen Lý do chính là s.replace('()','!')sẽ chỉ thay thế lần xuất hiện đầu tiên.
Arnauld

À, tất nhiên rồi. Quên JS thay thế không giống như Java. Trong Java .replacethay thế tất cả các lần xuất hiện và .replaceAllthay thế tất cả các lần xuất hiện khi bật regex. Luôn nghĩ rằng việc đặt tên khá tệ cho hai phương thức này trong Java, vì tôi sẽ gọi chúng .replaceAll.regexReplaceAllhoặc một cái gì đó dọc theo các dòng đó, nhưng tôi đoán đối với codegolf thì nó ngắn hơn .replace.replaceAll.
Kevin Cruijssen

1
BTW, tôi nhận thấy rằng bạn đang sử dụng cùng một kỹ thuật (với ~) ngay sau khi đăng phiên bản đầu tiên của câu trả lời của riêng tôi. Những bộ óc vĩ đại nghĩ giống nhau, tôi cho là vậy. : p
Arnauld

3

Sạch sẽ , 415 byte

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)

Hãy thử trực tuyến!


3

R , 225 218 byte

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())))))

Hãy thử trực tuyến!

Chương trình đầy đủ, được bao bọc trong một chức năng trên TIO để kiểm tra thuận tiện tất cả các trường hợp thử nghiệm cùng một lúc.

Thứ nhất, chúng tôi sử dụng Regex để chuyển đổi đầu vào của các hình thức type ...name...;để ..."name is"..."type". Ký hiệu chức năng ()sau đó được chuyển đổi thành văn bản với toán tử ghép nối có độ ưu tiên cao. Thật không may, chúng tôi cũng phải thay thế *bằng +như trước đây là không thể chấp nhận như một nhà điều hành unary. Phần còn lại được thực hiện bởi R evalvới các toán tử quá tải.


1
Giải pháp thông minh!
J.Doe

3

Perl 6 , 209 190 171 162 153 byte

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

Hãy thử trực tuyến!

Phương pháp regex đệ quy. Tạo ra một số ký tự không gian bổ sung có thể tránh được với giá 3 byte .

Giải trình

{     # 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 byte [249?]

Điều này sử dụng 250 byte:

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))

Giải trình:

Về cơ bản, nó đang đọc từ một bộ đệm a, là đầu vào token hóa. Nó liên tục di chuyển mã thông báo từ bộ đệm asang ngăn xếp s, cho đến khi chế độ đánh giá được kích hoạt. Chế độ đánh giá sẽ sử dụng các hoạt động hậu tố trước tiên (), []từ bộ đệm và sau đó nó sẽ sử dụng toán tử tiền tố *từ ngăn xếp. Chế độ đánh giá được kích hoạt khi trạng thái là nơi một từ (Hoặc là tên kiểu chữ được tìm thấy và tiêu thụ, hoặc một kết thúc )được tìm thấy và loại bỏ). Chế độ đánh giá bị vô hiệu hóa khi không tìm thấy thêm toán tử tiền tố / hậu tố.

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
)

GHI CHÚ

Nếu tôi hiểu "Sử dụng khoảng trắng ở mọi nơi giữa các mã thông báo" một cách chính xác:

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))

là hợp lệ về mặt kỹ thuật và sử dụng

249 byte

Giả sử rằng có một khoảng trống giữa mỗi mã thông báo.


2
Điều này khiến tôi mất nhiều giờ, mặc dù nó trông đơn giản. Tôi có thể gõ 5-10 byte / giờ, bắt đầu với 350 ký tự. Tôi thực sự không có cuộc sống.
Nicholas Pipitone

2
Tôi đã ở khoảng 325 khi tôi nghĩ rằng "Tôi đạt được sự tối ưu với thuật toán hiện tại của mình - rip", nhưng sau đó vì một số lý do, tôi vẫn có thể gõ 5-10 / giờ, mặc dù mỗi lần gõ đều theo sau "Được rồi, đây chắc chắn là kết quả tối ưu ". Đánh 250 là tùy ý vì đây là lần đầu tiên đánh bại triều đại 253, vì vậy mặc dù tôi vẫn nói "Được rồi, đây chắc chắn là kết quả tối ưu", vẫn có thể có nhiều hơn để tối ưu hóa.
Nicholas Pipitone

1

Màu đỏ , 418 410 byte

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]]

Hãy thử trực tuyến!

Giải trình:

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), ký tự 625, byte 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

đây chỉ là một sự chuyển đổi từ ngôn ngữ C sang APL từ mã trong cuốn sách: "Linguaggio C" của Brian W. Kerninghan và Dennis M. Ritchie chương 5.12. Tôi không biết làm thế nào để giảm tất cả điều đó bởi vì tôi đã không hiểu 100% mã đó và vì tôi không biết quá nhiều về APL ... Chức năng để thực hiện nó là f; tôi nghĩ rằng chỉ được phép 150 ngoặc đơn lồng nhau '(' ')' cho lỗi trả về một chuỗi với một giá trị âm trong đó hoặc giảm chuỗi nếu tất cả đều ổn. Có vẻ như điều này không tốt hơn phiên bản khác ngay cả khi ít ký tự hơn vì phiên bản kia thấy lỗi tốt hơn. Một số thử nghiệm:

  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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.