Monday, August 29, 2011

Exercise 1-24

Exercise 1-24  Write a program to check a C program for rudimentary syntax errors like unbalanced parentheses, brackets and braces.  Don't forget about quotes, both single and double, escape sequences, and comments.  (This program is hard if you do it in full generality.)

#include <stdio.h>
#include <stdlib.h>

/* For simplicity, this program doesn't deal with this case:
                  '\''                   */

enum states { NORMAL = 0, FORWARD_SLASH = 1, IN_COMMENT = 2,
              CLOSING_ASTERISK = 3, IN_QUOTE = 4, ESCAPING = 5,
              SINGLE_QUOTE = 6 };

int brackets = 0, parentheses = 0, braces = 0;

void print(int c)
{
  if (c!=EOF)
    putchar(c);

  switch(c)
  {
  case '(':
    parentheses++;
    break;

  case ')':
    parentheses--;
    break;

  case '[':
    brackets++;
    break;

  case ']':
    brackets--;
    break;

  case '{':
    braces++;
    break;

  case '}':
    braces--;
    break;

  default:
    break;
  }
}

enum states single_quote(int c)
{
  enum states state = SINGLE_QUOTE;

  switch(c)
  {
  default:
    state = SINGLE_QUOTE;
    print(c);
    break;

  case '\'':
    state = NORMAL;
    print(c);
    break;
  }

  return state;
}

enum states escaping(int c)
{
  print(c);  /* Regardless of what it is. */
  return NORMAL;
}

enum states in_quote(int c)
{
  enum states state = IN_QUOTE;

  switch(c)
  {
  case '\"':
    state = NORMAL;
    break;

  default:
    state = IN_QUOTE;
    break;
  }

  print(c);

  return state;
}

enum states closing_asterisk(int c)
{
  enum states state = IN_COMMENT;

  switch(c)
  {
  case '/':
    state = NORMAL;
    break;

  case '*':
    state = CLOSING_ASTERISK;
    break;

  default:
    state = IN_COMMENT;
    break;
  }

  return state;
}

enum states in_comment(int c)
{
  enum states state = IN_COMMENT;

  switch(c)
  {
  case '*':
    state = CLOSING_ASTERISK;
    break;

  default:
    state = IN_COMMENT;
    break;
  }

  return state;
}

enum states forward_slash(int c)
{
  enum states state = NORMAL;

  switch(c)
  {
  case '\'':
    state = SINGLE_QUOTE;
    break;

  case '/':
    print('/');
    state = FORWARD_SLASH;
    break;

  case '*':
    state = IN_COMMENT;
    break;

  default:
    state = NORMAL;
    print('/');
    print(c);
    break;
  }

  return state;
}

enum states normal(int c)
{
  enum states state = NORMAL;

  switch(c)
  {
  case '\'':
    state = SINGLE_QUOTE;
    print(c);
    break;

  case '\\':
    state = ESCAPING;
    print(c);
    break;

  case '\"':
    state = IN_QUOTE;
    print(c);
    break;

  case '/':
    state = FORWARD_SLASH;
    break;

  default:
    state = NORMAL;
    print(c);
    break;
  }

  return state;
}

enum states parse(int c, enum states state)
{
  enum states return_state = NORMAL;

  switch(state)
  {
  case SINGLE_QUOTE:
    return_state = single_quote(c);
    break;

  case IN_QUOTE:
    return_state = in_quote(c);
    break;

  case CLOSING_ASTERISK:
    return_state = closing_asterisk(c);
    break;

  case IN_COMMENT:
    return_state = in_comment(c);
    break;

  case FORWARD_SLASH:
    return_state = forward_slash(c);
    break;

  case NORMAL:
  default:
    return_state = normal(c);
    break;
  }

  return return_state;
}

int main(void)
{
  enum states state = NORMAL;
  int c;

  do
    state = parse(c = getchar(), state);
  while (c!=EOF);

  printf("\n");
  if (parentheses)
    printf("Unbalanced parentheses.\n");
  if (brackets)
    printf("Unbalanced brackets.\n");
  if (braces)
    printf("Unbalanced braces.\n");

  if (!parentheses && !brackets && !braces)
    printf("Looks good.\n");

  return EXIT_SUCCESS;
}

No comments:

Post a Comment