Permalink
Browse files

Basic prononciation

  • Loading branch information...
1 parent 138a221 commit 79e734079f72b04052c8be2e069c6a487eb07b50 @aartamonau committed Jul 25, 2010
Showing with 203 additions and 30 deletions.
  1. +203 −30 cdecl.c
View
233 cdecl.c
@@ -11,25 +11,33 @@
*/
+#include <assert.h>
+
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
+#include <stdbool.h>
/// Maximum length of the token that can be handled.
#define MAX_TOKEN_LEN 64
+/// Maximum number of tokens that can be handled.
+#define MAX_TOKENS 128
+
+
/// Defines possible tokens types.
enum token_type_t {
TYPE, /**< type declaration */
SPECIFIER, /**< type specifier */
IDENTIFIER, /**< identifier */
ARRAY, /**< array */
POINTER, /**< pointer */
- FUNCTION, /**< function */
+ LBRACE, /**< left brace */
+ RBRACE, /**< right brace */
END, /**< declaration finishied */
};
@@ -49,7 +57,8 @@ token_to_str(enum token_type_t type)
"IDENTIFIER",
"ARRAY",
"POINTER",
- "FUNCTION",
+ "LBRACE",
+ "RBRACE",
"END" };
return strs[type];
@@ -60,11 +69,12 @@ token_to_str(enum token_type_t type)
struct token_t {
enum token_type_t type; /**< type of the token */
- char str[MAX_TOKEN_LEN + 1]; /**< string representation of the token */
+
union {
- int size; /**< if ::type is #ARRAY then it's the size of
- * array (or -1 in case size has not been
- * specified)*/
+ char name[MAX_TOKEN_LEN + 1]; /**< string representation of the token */
+ int size; /**< if ::type is #ARRAY then it's the size
+ * of array (or -1 in case size has not been
+ * specified) */
} info;
};
@@ -74,6 +84,11 @@ static int position = 0; /**< current position in the line */
static struct token_t token; /**< current token */
+static struct token_t stack[MAX_TOKENS]; /**< stack of tokens to the left from
+ * curent one*/
+static int head = 0; /**< head of the #stack */
+
+
/**
* Prints a message about fatal condition and exits with #EXIT_FAILURE exit
* code.
@@ -105,6 +120,54 @@ fatal(const char *format, ...)
/**
+ * Pushes a token to the #stack.
+ *
+ * @param token token
+ */
+static void
+stack_push(const struct token_t *token)
+{
+ if (head >= MAX_TOKENS) {
+ fatal("Too long declaration. Can't proceed.\n");
+ }
+
+ stack[head++] = *token;
+}
+
+
+/**
+ * Pops a token from the #stack.
+ *
+ *
+ * @return token
+ */
+static struct token_t
+stack_pop(void)
+{
+ /* can be a programming error actually */
+ if (head == 0) {
+ fatal("Stack underflow. Invalid declaration.\n");
+ }
+
+ return stack[--head];
+}
+
+
+/**
+ * Determines whether #stack is empty.
+ *
+ *
+ * @retval true Stack is empty.
+ * @retval false Stack is not empty.
+ */
+static bool
+stack_is_empty(void)
+{
+ return head == 0;
+}
+
+
+/**
* Wrapper for getchar() function which keeps #line and #position consistent.
*
*
@@ -216,6 +279,10 @@ skip_to_char(char end)
}
+/**
+ * Reads token from @e stdin and stores it in #token.
+ *
+ */
void
get_token()
{
@@ -228,27 +295,25 @@ get_token()
fatal_pos("Unexpected end of file\n");
} else if (c == ';') {
token.type = END;
- token.str[0] = ';';
- token.str[1] = '\0';
} else if (isalpha(c)) {
/* some type, specifier or declarator starts here */
_ungetchar(c);
- get_id(token.str);
-
- if (strcmp(token.str, "int") == 0 ||
- strcmp(token.str, "char") == 0 ||
- strcmp(token.str, "void") == 0 ||
- strcmp(token.str, "signed") == 0 ||
- strcmp(token.str, "unsigned") == 0 ||
- strcmp(token.str, "short") == 0 ||
- strcmp(token.str, "long") == 0 ||
- strcmp(token.str, "float") == 0 ||
- strcmp(token.str, "double") == 0)
+ get_id(token.info.name);
+
+ if (strcmp(token.info.name, "int") == 0 ||
+ strcmp(token.info.name, "char") == 0 ||
+ strcmp(token.info.name, "void") == 0 ||
+ strcmp(token.info.name, "signed") == 0 ||
+ strcmp(token.info.name, "unsigned") == 0 ||
+ strcmp(token.info.name, "short") == 0 ||
+ strcmp(token.info.name, "long") == 0 ||
+ strcmp(token.info.name, "float") == 0 ||
+ strcmp(token.info.name, "double") == 0)
{
token.type = TYPE;
- } else if (strcmp(token.str, "const") == 0 ||
- strcmp(token.str, "volatile") == 0)
+ } else if (strcmp(token.info.name, "const") == 0 ||
+ strcmp(token.info.name, "volatile") == 0)
{
token.type = SPECIFIER;
} else {
@@ -258,26 +323,134 @@ get_token()
skip_to_char(']');
token.type = ARRAY;
- *token.str = '\0';
/* for now all arrays are without size */
token.info.size = -1;
} else if (c == '(') {
- skip_to_char(')');
- token.type = FUNCTION;
- *token.str = '\0';
- /* similarly, all the function parameters are ignored for now */
+ token.type = LBRACE;
+ } else if (c == ')') {
+ token.type = RBRACE;
+ } else if (c == '*') {
+ token.type = POINTER;
}
}
-int
-main(void)
+/**
+ * Pronounces single token.
+ *
+ * @param token A token to pronounce.
+ */
+static void
+pronounce_token(const struct token_t *token)
+{
+ switch (token->type) {
+ case TYPE:
+ printf("%s ", token->info.name);
+ break;
+ case SPECIFIER:
+ if (strcmp(token->info.name, "const") == 0) {
+ printf("read-only ");
+ } else {
+ printf("%s ", token->info.name);
+ }
+ break;
+ case ARRAY:
+ printf("array of ");
+ break;
+ case POINTER:
+ printf("pointer to ");
+ break;
+ case LBRACE:
+ printf("function returning ");
+ break;
+ case RBRACE:
+ case END:
+ /* just keeping silence */
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+/**
+ * Tries to "pronounce" @e C declaration read from @e stdin in
+ * human-understandable form.
+ *
+ */
+static void
+pronounce(void)
{
do {
get_token();
- printf("Token type: %s, source: %s\n", token_to_str(token.type), token.str);
+ stack_push(&token);
+ } while (token.type != IDENTIFIER);
+
+ /* popping identifier */
+ stack_pop();
+
+ printf("%s is ", token.info.name);
+
+ /* whether input to the right of identifier is finished */
+ bool right_finished = false;
+ bool left_finished = false;
+
+ while (true) {
+ /* right pass */
+ if (!right_finished) {
+ do {
+ get_token();
+ pronounce_token(&token);
+
+ /* skiping function argument */
+ if (token.type == LBRACE) {
+ do {
+ get_token();
+ } while (token.type != RBRACE);
+
+ /* faking token type to proceed to the right */
+ token.type = LBRACE;
+ }
+ } while (token.type != END &&
+ token.type != RBRACE);
+
+ /* we reached the end of input */
+ if (token.type == END) {
+ right_finished = true;
+ }
+ }
- } while (token.type != END);
+ /* left pass */
+ if (!left_finished) {
+ struct token_t left_token;
+ do {
+ left_token = stack_pop();
+
+ /* left brace should not be pronounced as "function" */
+ if (left_token.type != LBRACE) {
+ pronounce_token(&left_token);
+ }
+ } while (!stack_is_empty() &&
+ left_token.type != LBRACE);
+
+ if (stack_is_empty()) {
+ left_finished = true;
+ }
+ }
+
+ if (left_finished && right_finished) {
+ break;
+ }
+ }
+
+ printf("\n");
+}
+
+
+int
+main(void)
+{
+ pronounce();
return EXIT_SUCCESS;
}

0 comments on commit 79e7340

Please sign in to comment.