-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
352 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
cdecl | ||
*.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
CFLAGS = -Wall | ||
|
||
all: cdecl doc | ||
|
||
cdecl: main.c | ||
$(CC) $(CFLAGS) -o $@ $^ | ||
|
||
debug: CFLAGS += -g | ||
debug: cdecl | ||
|
||
doc: cdecl.1 | ||
|
||
cdecl.1: cdecl.pod | ||
@echo -- Generating manpage from POD: | ||
pod2man --section=1 --center="cdecl" $? $@ | ||
|
||
.PHONY: clean | ||
clean: | ||
-rm -f cdecl | ||
-rm -f *.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# cdecl - C Declarations Translator | ||
|
||
`cdecl` translates C declarations to plain English. | ||
|
||
Throughout the history of the C language, this program has been written many | ||
times in different versions with varying levels of complexity and features. | ||
This one in particular uses an algorithm developed by Peter van der Linden, | ||
presented in his book *Expert C Programming*<sup>[1]</sup>. Writing the | ||
program is given as an exercise in his book. | ||
|
||
## Installing | ||
|
||
#### On macOS with [Homebrew][brw] | ||
|
||
$ brew install tessarin/core/cdecl | ||
|
||
#### Manual Installation | ||
|
||
Run `make` to compile the program and generate the manual page. Then, move the | ||
files to your desired and appropriate locations on your system: | ||
|
||
$ make | ||
$ mv cdecl ~/bin | ||
$ mv cdecl.1 ~/man/man1 | ||
|
||
## Usage | ||
|
||
Call `cdecl` passing the declaration or write it directly in your terminal. | ||
The program will process the declaration and exit at the end of the first | ||
line. | ||
|
||
$ cdecl | ||
|
||
For more information including the types and features recognized by the | ||
program check the [manual][man]. | ||
|
||
## Examples | ||
|
||
$ cdecl | ||
long * const c | ||
c is readonly pointer to long | ||
|
||
$ cdecl | ||
int *(*fn())() | ||
fn is function returning pointer to function returning pointer to int | ||
|
||
$ cdecl | ||
short *(*(* const x)[3])() | ||
x is readonly pointer to array with size 3 of pointer to function returning pointer to short | ||
|
||
--- | ||
|
||
<sup>[1]</sup> **Expert C Programming - Deep C Secrets**, 1st edition | ||
Peter van der Linden | ||
© 1994 Sun Microsystems, Inc. | ||
ISBN 978-0-131-77429-2 | ||
|
||
[brw]: https://brew.sh | ||
[man]: cdecl.pod |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
=head1 NAME | ||
|
||
B<cdecl> -- Translate C declarations to English | ||
|
||
=head1 SYNOPSIS | ||
|
||
B<cdecl> | ||
|
||
=head1 DESCRIPTION | ||
|
||
B<cdecl> reads a C declaration from its input and translates it to English | ||
terms which are sent as output. | ||
|
||
This program was written following the recommendations and algorithm presented | ||
by Peter van der Linden on his book "Expert C Programming - Deep C Secrets". | ||
Writing this program was a programming challenge given in Chapter 3. | ||
|
||
There have been many C<cdecl> versions written along history. This one in | ||
particular -- although very simple -- has an easy to understand parsing algorithm | ||
and is relatively complete. Recognized types include: | ||
|
||
void | ||
char | ||
short | ||
int | ||
long | ||
signed | ||
unsigned | ||
float | ||
double | ||
struct | ||
union | ||
enum | ||
|
||
And the following language features: | ||
|
||
=over 6 | ||
|
||
=item - I<Arrays> | ||
|
||
Interpreted with or without any size. | ||
|
||
=item - I<Functions> | ||
|
||
Interpreted with arguments ignored. | ||
|
||
=item - I<Qualifiers> | ||
|
||
Both C<volatite> and C<const> (which is translated as I<readonly>) | ||
|
||
=item - I<Pointers> | ||
|
||
=back | ||
|
||
=head1 EXAMPLES | ||
|
||
Calling the program and writing the declaration followed by a new line will | ||
produce, for example: | ||
|
||
$ cdecl | ||
int * const n | ||
n is readonly pointer to int | ||
|
||
$ cdecl | ||
char *f() | ||
f is function returning pointer to char | ||
|
||
$ cdecl | ||
long *(*(*x)[10])() | ||
x is pointer to array with size 10 of pointer to function returning pointer to long | ||
|
||
=head1 CAVEATS | ||
|
||
Due to the way it is constructed, this version of C<cdecl> won't produce any | ||
warning or error if bad syntax is encountered. There are no checks for invalid | ||
constructs either, such as an array of functions. | ||
|
||
The goal (as described in the book) was not to build a complete parser but | ||
rather implement and practice an easy algorithm. | ||
|
||
=head1 AUTHORS & HISTORY | ||
|
||
This software and manual were written by Cesar Tessarin originally on July 5th | ||
2011, rewritten partially and updated on Oct. 2017. However, all credit of the | ||
internal algorithm and design goes to Peter van der Linden since (as stated | ||
above) this was an exercise from his book: | ||
|
||
B<Expert C Programming - Deep C Secrets>, 1st edition | ||
|
||
Peter van der Linden | ||
(C) 1994 Sun Microsystems, Inc. | ||
ISBN:978-0-131-77429-2 | ||
|
||
=cut |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <ctype.h> | ||
|
||
#define MAXTOKENLEN 64 | ||
#define MAXTOKENS 128 | ||
|
||
struct token { | ||
char type; | ||
char string[MAXTOKENLEN]; | ||
}; | ||
|
||
enum token_type { | ||
TYPE, | ||
QUALIFIER, | ||
IDENTIFIER | ||
}; | ||
|
||
/* main token stack */ | ||
struct token stack[MAXTOKENS]; | ||
int stack_index = -1; | ||
|
||
#define push(A) stack[++stack_index] = (A) | ||
#define pop stack[stack_index--] | ||
#define current stack[stack_index] | ||
|
||
/* current token */ | ||
struct token this; | ||
|
||
/* returns the type of the current token */ | ||
enum token_type | ||
classify_string() | ||
{ | ||
char *str = this.string; | ||
|
||
if ( !strcmp(str, "void") | ||
|| !strcmp(str, "char") | ||
|| !strcmp(str, "short") | ||
|| !strcmp(str, "int") | ||
|| !strcmp(str, "long") | ||
|| !strcmp(str, "signed") | ||
|| !strcmp(str, "unsigned") | ||
|| !strcmp(str, "float") | ||
|| !strcmp(str, "double") | ||
|| !strcmp(str, "struct") | ||
|| !strcmp(str, "union") | ||
|| !strcmp(str, "enum") | ||
) return TYPE; | ||
|
||
if (!strcmp(str, "volatile")) | ||
return QUALIFIER; | ||
|
||
if (!strcmp(str, "const")) { | ||
strcpy(str, "readonly"); | ||
return QUALIFIER; | ||
} | ||
|
||
return IDENTIFIER; | ||
} | ||
|
||
/* reads the next token into `this` and classify it */ | ||
void | ||
get_token() | ||
{ | ||
char *str = this.string; | ||
|
||
/* discard whitespace */ | ||
do { | ||
*str = getchar(); | ||
} while (*str == ' ' || *str == '\t'); | ||
|
||
if (isalnum(*str)) { | ||
/* read the rest */ | ||
while (isalnum(*++str = getchar())) ; | ||
ungetc(*str, stdin); | ||
*str = '\0'; | ||
|
||
this.type = classify_string(); | ||
return; | ||
} | ||
|
||
/* for other not alnum the token type is itself */ | ||
this.type = *str; | ||
*++str = '\0'; | ||
|
||
return; | ||
} | ||
|
||
void | ||
read_to_first_identifier() | ||
{ | ||
do { | ||
get_token(); | ||
push(this); | ||
} while (this.type != IDENTIFIER); | ||
|
||
printf("%s is ", this.string); | ||
pop; | ||
|
||
get_token(); | ||
} | ||
|
||
/* --- Parsing Routines --- | ||
* | ||
* Work on the current token and always | ||
* read the next one at the end. | ||
*/ | ||
|
||
void | ||
deal_with_function_args() | ||
{ | ||
/* read past closing `)` */ | ||
while (this.type != ')') get_token(); | ||
get_token(); | ||
|
||
printf("function returning "); | ||
} | ||
|
||
void | ||
deal_with_arrays() | ||
{ | ||
printf("array "); | ||
get_token(); /* read size or `]` */ | ||
|
||
/* print size if given */ | ||
if (isdigit(*this.string)) { | ||
printf("with size %s ", this.string); | ||
get_token(); /* read `]` */ | ||
} | ||
|
||
printf("of "); | ||
get_token(); | ||
} | ||
|
||
/* prints pointers on stack, if any */ | ||
void | ||
deal_with_pointers() | ||
{ | ||
while (current.type == '*') { | ||
printf("pointer to "); | ||
pop; | ||
} | ||
} | ||
|
||
void | ||
deal_with_declarator() | ||
{ | ||
if (this.type == '[') | ||
deal_with_arrays(); | ||
|
||
if (this.type == '(') | ||
deal_with_function_args(); | ||
|
||
/* while there is content on the stack */ | ||
while (stack_index >= 0) { | ||
deal_with_pointers(); | ||
if (current.type == '(') { | ||
/* simple parenthesis */ | ||
pop; | ||
get_token(); /* should be the matching `)` */ | ||
deal_with_declarator(); | ||
} else { | ||
printf("%s ", pop.string); | ||
} | ||
} | ||
} | ||
|
||
int | ||
main(int argc, char **argv) | ||
{ | ||
read_to_first_identifier(); | ||
deal_with_declarator(); | ||
|
||
printf("\n"); | ||
|
||
return 0; | ||
} |