The C language itself provides a less explicit way of declaring variables-based on the use of declarations, such as int *a, which essentially declares the type of *a to be int, so a pointer to an int is obtained. For simple types, this declaration does not have much of a reading barrier to the code, and for complex declarations such as the signal function signature of the standard library, void (*signal (int sig, void (*handler))) (int), what is this? At a glance, this is a function that accepts two arguments, an int, a function pointer, and this function pointer to a function that takes an int and returns void; Returns a function pointer to the function that the function pointer points to takes an int and returns void. Although a lot of people are arguing that the project who wrote such a code to fire him, but the standard library is indeed written out of such code, what do you do?
To parse such a complex declaration, I have seen a method-right rotation method-in this way:
- Starting with the variable name, right and left, alternately, one at the side of the token, write on the paper: "Variable is"
- If you encounter the left parenthesis to the right, write down on the paper: "Function, parameter is", and use the same method to handle each parameter in parentheses--write on the paper: "Back"
- If you encounter square brackets to the right, write down on the paper: "Array, length {square brackets}, Element type"
- If you see right parenthesis to the right, do nothing.
- If you encounter * on the left, write on the paper: "Pointer, point to"
- If any type is encountered on the left, write down the corresponding type name on the paper
We use this method to process the following statement
void* (* (*FP1) (int)) [10]
- From FP1 onwards--FP1 is
- Right, I get a closing parenthesis, I don't do anything.
- Left, encounter the *--pointer, point to
- To the right, you encounter the left parenthesis--function, the argument is int, return
- Left, encounter the *--pointer, point to
- To the right, the left bracket is encountered--array, length 10, element type
- Left, encounter the *--pointer, point to
- Right, already to the end of the declaration, do nothing
- Left, Encounter void--void
The result is: FP1 is a pointer to a function, a parameter is an int, a pointer is returned, an array is a length of 10, the element type is a pointer, and a point is a void
This method is more suitable for people, because he is more in line with the human brain processing, but also a little disadvantage, if the function of the formal parameters also write the name, not very skilled small white, it is not easy to find the correct starting position, resulting in the chaos of processing.
For machine processing, this method from the middle to the sides is not very suitable, because the machine can not directly in a token sequence to find the starting position of processing, he can only from left to right to scan, I last night brainwave thought of an algorithm, today conducted a test, the effect is good, No comparison with some such as cdecl.org, such as the open source implementation, I this algorithm is only a demo, does not fully support the C Declaration of processing, address here.
Algorithm from left to right scanning, essentially recursive descent, the basic process is this, for the convenience of explanation, the recursive function named parse:
- Parse begins
- If encountered type, save into variable A, recursive parse, output a
- Elif encountered *, recursive parse, output "pointer to"
- Elif encounters a left parenthesis, recursively parse, and checks for parentheses to match
- Elif encountered identifier, output "{identifier} is"
- Control Flow continues
- If you encounter the opening parenthesis, output "array with length {length} of" and check that the parentheses match
- Elif encounters the left parenthesis, outputs "function accepting", iterates over the parse, eats the trailing comma until the right parenthesis is encountered, and outputs "returning"
- Return
What is the meaning of recursion? The meaning of each parse function is: "I deal with the type of this thing is-", the right side of the dash after the function exits the upper layer function to complete, so go back to the above algorithm, encountered a type of time, I understand that I am dealing with the next layer of the type of the object is an int, So I recursively call parse and output int.
From the perspective of cyclic invariant, parse is the only one of the exits, and that is the first if, whatever the function declaration, ends with a variable, and here is the only one to say all branches--the other branches are output similar to "XXX is", " XXX return "So did not say the words, so the parse to ensure that the last layer of the words are not finished-from not the first if the branch exit, from this layer to fill the words, this is a sense of the loop invariant bar.
Finally, I split the above statement into different layers to show the parse process.
void * [ten] ( ) * (int) ( ) * FP1
On the analysis of C language variable declaration