aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ch6/6-05_undef.c3
-rw-r--r--ch6/6-06_define-processor.c199
2 files changed, 200 insertions, 2 deletions
diff --git a/ch6/6-05_undef.c b/ch6/6-05_undef.c
index 9ffd248..d65f435 100644
--- a/ch6/6-05_undef.c
+++ b/ch6/6-05_undef.c
@@ -5,7 +5,7 @@
/* The C Programming Language: 2nd Edition
*
* Exercise 6-5: Write a function `undef` that will remove a name and
- * definition from the table maintai\ed by lookup() and install().
+ * definition from the table maintained by lookup() and install().
*
* Notes: since undef() operates on the same data structure as lookup()
* and install(), I chose to depend on lookup() to find the correct node
@@ -27,7 +27,6 @@ unsigned hash(char *);
struct nlist *install(char *, char *);
struct nlist *lookup(char *);
int undef(char *);
-void print_table(struct nlist *);
int main(int argc, char **argv) {
/* Install a few words */
diff --git a/ch6/6-06_define-processor.c b/ch6/6-06_define-processor.c
new file mode 100644
index 0000000..d26ddbc
--- /dev/null
+++ b/ch6/6-06_define-processor.c
@@ -0,0 +1,199 @@
+#include <stdio.h>
+#include <string.h> // strdup, strcmp
+#include <stdlib.h> // malloc, free
+
+/* The C Programming Language: 2nd Edition
+ *
+ * Exercise 6-6: Implement a simple version of the `#define` processor
+ * (i.e., no arguments) suitable for use with C programs, based on the
+ * routines of this section. You may also find getch() and ungetch()
+ * helpful.
+ *
+ * Notes: The routines this exercise is talking about are lookup() and
+ * install(), which were used in 6-5. It also depends on the 'nlist'
+ * data structure that those functions used. It's unclear what is meant
+ * by "#define processor", so I opted for a simple string replacement
+ * implementation. It only accepts one alpha-numeric name and one alpha-
+ * numeric replacement, so nowhere *near* correctly supporting #define,
+ * but it fulfills the requirements. There's room for improvement here,
+ * for sure.
+ */
+
+#define HASHSIZE 101
+#define MAXWORD 65
+#define BUFSIZE 40
+
+struct nlist {
+ struct nlist *next;
+ char *name;
+ char *defn;
+};
+
+static struct nlist *hashtab[HASHSIZE];
+enum states {
+ NORMAL,
+ INQUOTE,
+ COMMENT_PART_IN,
+ COMMENT_PART_OUT,
+ ONELINE_COMMENT,
+ INCOMMENT
+};
+static char buf[BUFSIZE];
+static int bufp = 0;
+int state = NORMAL;
+
+unsigned hash(char *);
+struct nlist *install(char *, char *);
+struct nlist *lookup(char *);
+int getch(void);
+void ungetch(int);
+int getword(char *, int);
+
+int main() {
+ char *word = malloc(sizeof(char) * MAXWORD);
+ struct nlist *def;
+ int define_phase = 0;
+ char *name;
+ char *desc;
+ while (getword(word, MAXWORD) != EOF) {
+ if (state == NORMAL && strcmp(word, "#define") == 0) {
+ define_phase = 1;
+ printf("%s", word);
+ continue;
+ }
+ if (define_phase == 1) {
+ name = strdup(word);
+ define_phase = 2;
+ printf("%s", word);
+ continue;
+ }
+ if (define_phase == 2) {
+ desc = strdup(word);
+ define_phase = 0;
+ printf("%s", word);
+ install(name, desc);
+ continue;
+ }
+ if (state == NORMAL && (def = lookup(word)) != NULL) {
+ printf("%s", def->defn);
+ continue;
+ }
+ printf("%s", word);
+ }
+}
+
+/* form hash value for string s */
+unsigned hash(char *s) {
+ unsigned hashval;
+ for (hashval = 0; *s != '\0'; s++) {
+ hashval = *s + 31 * hashval;
+ }
+ return hashval % HASHSIZE;
+}
+
+/* Look for s in hashtab */
+struct nlist *lookup(char *s) {
+ struct nlist *np;
+ for (np = hashtab[hash(s)]; np != NULL; np = np->next) {
+ if (strcmp(s, np->name) == 0) {
+ return np;
+ }
+ }
+ return NULL;
+}
+
+/* put name and defn in hashtab */
+struct nlist *install(char *name, char *defn) {
+ struct nlist *np;
+ unsigned hashval;
+ if ((np = lookup(name)) == NULL) {
+ np = (struct nlist *) malloc(sizeof(*np));
+ if (np == NULL || (np->name = strdup(name)) == NULL) {
+ return NULL;
+ }
+ hashval = hash(name);
+ np->next = hashtab[hashval];
+ hashtab[hashval] = np;
+ } else {
+ free ((void *) np->defn);
+ }
+ if ((np->defn = strdup(defn)) == NULL) {
+ return NULL;
+ }
+ return np;
+}
+
+int getch(void) {
+ return (bufp > 0) ? buf[--bufp] : getchar();
+}
+
+void ungetch(int c) {
+ if (bufp >= BUFSIZE) {
+ printf("ungetch: Too many characters.\n");
+ } else {
+ buf[bufp++] = c;
+ }
+}
+
+int getword(char *word, int lim) {
+ int c;
+ char *w = word;
+ while (isspace(c = getch())) {
+ if (c == '\n' && state == ONELINE_COMMENT) {
+ state = NORMAL;
+ }
+ putchar(c);
+ }
+ if (c != EOF) {
+ *w++ = c;
+ } else {
+ return EOF;
+ }
+ switch (c) {
+ case '/':
+ switch (state) {
+ case NORMAL:
+ state = COMMENT_PART_IN;
+ break;
+ case COMMENT_PART_IN:
+ state = ONELINE_COMMENT;
+ break;
+ case COMMENT_PART_OUT:
+ state = NORMAL;
+ break;
+ }
+ break;
+ case '*':
+ switch (state) {
+ case INCOMMENT:
+ state = COMMENT_PART_OUT;
+ break;
+ case COMMENT_PART_IN:
+ state = INCOMMENT;
+ break;
+ }
+ break;
+ case '"':
+ switch (state) {
+ case NORMAL:
+ state = INQUOTE;
+ break;
+ case INQUOTE:
+ state = NORMAL;
+ break;
+ }
+ break;
+ }
+ if (!isalnum(c) && c != '#') {
+ *w = '\0';
+ return c;
+ }
+ for ( ; --lim > 0; w++) {
+ if (!isalnum(*w = getch())) {
+ ungetch(*w);
+ break;
+ }
+ }
+ *w = '\0';
+ return word[0];
+}