HOME

Expression compiler

Given a expression this compiler generates C code that solves the expression and also reports errors.


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


struct stream
{
  const char* p;
};
#define ch(S) (*(S)->p)
#define match(S) ((S)->p++)

void parse_expression(struct stream* stream, char* r);

void parse_value(struct stream* stream, char* left)
{

  if (ch(stream) >= '0' && ch(stream) <= '9')
  {
    while (ch(stream) >= '0' && ch(stream) <= '9')
    {
      *left = ch(stream);
      left++;
      match(stream);
    }
    *left = 0;
  }
  else if (ch(stream) >= 'a' && ch(stream) <= 'z')
  {
    while (ch(stream) >= 'a' && ch(stream) <= 'z')
    {
      *left = ch(stream);
      left++;
      match(stream);
    }
    *left = 0;
  }
  else if (ch(stream) == '(')
  {
    match(stream);
    parse_expression(stream, left);
    match(stream);
  }
  else
  {
    //error
  }
}

void parse_expression(struct stream* stream, char* right)
{
  char left[100];


  if ((ch(stream) >= '0' && ch(stream) <= '9') ||
      (ch(stream) >= 'a' && ch(stream) <= 'z') ||
      ch(stream) == '(')
  {
    parse_value(stream, left);
  }
  else
  {
    parse_expression(stream, left);
  }

  char op = ch(stream);
  if (op == '*' || op == '/')
  {

    match(stream);
    parse_expression(stream, right);
    if (op == '*')
    {
      printf("  if((%s == -1) && (%s == INT_MIN)) /*overflow */ return 1;\n", left, right);
      printf("  if((%s == -1) && (%s == INT_MIN)) /*overflow */ return 1;\n", right, left);
      printf("  if(%s > INT_MAX / %s) /* overflow */ return 1;\n", left, right);
      printf("  if(%s < INT_MIN / %s) /* overflow */ return 1;\n", left, right);
    }
    else
    {
      printf("  if((%s == INT_MIN) && (%s == -1)) /* a / b would overflow */ return 1;\n", left, right);
    }
    printf("  r = %s %c %s;\n\n", left, op, right);

    strcpy(right, "r");
  }
  else if (op == '+' || op == '-')
  {


    match(stream);
    parse_expression(stream, right);
    if (op == '+')
    {
      printf("  if ((%s > 0) && (%s > INT_MAX - %s)) return 1; /*overflow*/\n", right, left, right);
      printf("  if ((%s < 0) && (%s < INT_MIN - %s)) return 1; /*underflow*/\n", right, left, right);
    }
    else
    {
      printf("  if ((%s < 0) && (%s > INT_MAX + %s)) return 1;\n", right, left, right);
      printf("  if ((%s > 0) && (%s < INT_MAX + %s)) return 1;\n", right, left, right);
    }

    printf("  r = %s %c %s;\n\n", left, op, right);
    strcpy(right, "r");
  }
  else
  {
    strcpy(right, left);
  }

}

void solve(const char* p)
{
  struct stream s = {.p = p};

  printf("\n");
  printf("/*%s*/\n", p);
  printf("int solve(int* result)\n");
  printf("{\n");
  printf("  int r;\n");

  char r[100];
  parse_expression(&s, r);

  printf("  *result = r;\n");
  printf("  return 0;\n");
  printf("}\n");
  printf("\n");
}

int main()
{
  for (;;)
  {
    char input[128] = {0};
    printf("> ");
    gets(input);
    solve(input);
  }
}

/*a+b*c*/
int solve(int* result)
{
  int r;
  if((b == -1) && (c == INT_MIN)) /*overflow */ return 1;
  if((c == -1) && (b == INT_MIN)) /*overflow */ return 1;
  if(b > INT_MAX / c) /* overflow */ return 1;
  if(b < INT_MIN / c) /* overflow */ return 1;
  r = b * c;

  if ((r > 0) && (a > INT_MAX - r)) return 1; /*overflow*/
  if ((r < 0) && (a < INT_MIN - r)) return 1; /*underflow*/
  r = a + r;

  *result = r;
  return 0;
}