diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..40acb59
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+cdecl
+*.1
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0786982
--- /dev/null
+++ b/Makefile
@@ -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
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b7d43cf
--- /dev/null
+++ b/README.md
@@ -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*[1]. 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
+
+---
+
+[1] **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
diff --git a/cdecl.pod b/cdecl.pod
new file mode 100644
index 0000000..247cd18
--- /dev/null
+++ b/cdecl.pod
@@ -0,0 +1,94 @@
+=head1 NAME
+
+B -- Translate C declarations to English
+
+=head1 SYNOPSIS
+
+B
+
+=head1 DESCRIPTION
+
+B 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 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
+
+Interpreted with or without any size.
+
+=item - I
+
+Interpreted with arguments ignored.
+
+=item - I
+
+Both C and C (which is translated as I)
+
+=item - I
+
+=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 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, 1st edition
+
+Peter van der Linden
+(C) 1994 Sun Microsystems, Inc.
+ISBN:978-0-131-77429-2
+
+=cut
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..27f560c
--- /dev/null
+++ b/main.c
@@ -0,0 +1,177 @@
+#include
+#include
+#include
+
+#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;
+}