Skip to content

Commit

Permalink
Completed hand-written parser example.
Browse files Browse the repository at this point in the history
  • Loading branch information
dthain committed Aug 15, 2019
1 parent 3d946f4 commit b5d1eb9
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 1 deletion.
18 changes: 18 additions & 0 deletions chapter4/hand-written/Makefile
@@ -0,0 +1,18 @@

# The top level rule indicates how to link everything together into calc

calc: main.o scanner.o parser.o
gcc main.o scanner.o parser.o -o calc -lm

# This pattern indicates that any .o file depends
# upon the .c file of the same name, and all of the .h files.
# So, if a .o file is needed, it is built automatically.

%.o: %.c *.h
gcc -Wall -c -g $< -o $@

# clean causes all intermediate files to be deleted.

clean:
rm -f *.o calc

15 changes: 15 additions & 0 deletions chapter4/hand-written/README.md
@@ -0,0 +1,15 @@
Hand-Written LL(1) Parser and Scanner
-------------------------------------

This shows a simple example of a hand-written scanner
and a hand-written recursive-descent parser for an LL(1)
expression language. The program attempts to parse the
input and determine whether the parse succeeds, but
does not evaluate the expression.

Some suggested exercises:
- Modify the program to compute the value of the expression, if it parses.

- Modify the scanner and parser to handle more complex expressions,
such as floating point values and additional operators.

15 changes: 15 additions & 0 deletions chapter4/hand-written/main.c
@@ -0,0 +1,15 @@
#include "parser.h"
#include <stdio.h>

int main()
{
printf("Enter an expression, followed by Control-D to indicate EOF.\n");
if(parse_P()) {
printf("Expression is valid.\n");
return 0;
} else {
printf("Expression is NOT valid.\n");
return 1;
}
}

8 changes: 7 additions & 1 deletion chapter4/rdp.c → chapter4/hand-written/parser.c
@@ -1,3 +1,9 @@

#include "parser.h"
#include "scanner.h"

#include <stdio.h>

int parse_P()
{
return parse_E() && expect_token(TOKEN_EOF);
Expand Down Expand Up @@ -43,7 +49,7 @@ int parse_F()
} else if(t == TOKEN_INT) {
return 1;
} else {
printf("parse error: unexpected token %s\n", token_string(t));
printf("parse error: unexpected token: %s", token_string(t));
return 0;
}
}
11 changes: 11 additions & 0 deletions chapter4/hand-written/parser.h
@@ -0,0 +1,11 @@
#ifndef PARSER_H
#define PARSER_H

int parse_P();
int parse_E();
int parse_E_prime();
int parse_T();
int parse_T_prime();
int parse_F();

#endif
79 changes: 79 additions & 0 deletions chapter4/hand-written/scanner.c
@@ -0,0 +1,79 @@
#include "scanner.h"
#include <stdio.h>
#include <ctype.h>

static int putback_valid = 0;
static token_t putback_value = TOKEN_ERROR;

token_t scan_token()
{
if(putback_valid) {
putback_valid = 0;
return putback_value;
}

int c;
retry:
c = fgetc(stdin);

if(c=='*') {
return TOKEN_MULTIPLY;
} else if(c=='+') {
return TOKEN_PLUS;
} else if(c=='(') {
return TOKEN_LPAREN;
} else if(c==')') {
return TOKEN_RPAREN;
} else if(isdigit(c)) {
do {
c = fgetc(stdin);
} while(isdigit(c));
ungetc(c,stdin);
return TOKEN_INT;
} else if(isspace(c)) {
goto retry;
} else if(c==EOF) {
return TOKEN_EOF;
} else {
return TOKEN_ERROR;
}
}

int expect_token( token_t kind )
{
token_t t = scan_token();
if(t==kind) {
return 1;
} else {
putback_token(t);
return 0;
}
}

void putback_token( token_t t )
{
putback_value = t;
putback_valid = 1;
}

const char * token_string( token_t t )
{
switch(t) {
case TOKEN_MULTIPLY:
return "*";
case TOKEN_PLUS:
return "+";
case TOKEN_LPAREN:
return "(";
case TOKEN_RPAREN:
return ")";
case TOKEN_INT:
return "INTEGER";
case TOKEN_EOF:
return "EOF";
case TOKEN_ERROR:
default:
return "ERROR";
}
}

19 changes: 19 additions & 0 deletions chapter4/hand-written/scanner.h
@@ -0,0 +1,19 @@
#ifndef SCANNER_H
#define SCANNER_H

typedef enum {
TOKEN_PLUS,
TOKEN_MULTIPLY,
TOKEN_LPAREN,
TOKEN_RPAREN,
TOKEN_INT,
TOKEN_ERROR,
TOKEN_EOF
} token_t;

token_t scan_token();
int expect_token( token_t t );
void putback_token( token_t t );
const char * token_string( token_t t );

#endif

0 comments on commit b5d1eb9

Please sign in to comment.