1

I have the following code, where I want to create a simply scanner for a simple calculator language. I am using fgetc to get the character from the file. Though, at some places I also need to check the next character that is followed. For this reason I have been using the ++ operator, but it seems like it is not working properly. Can someone help me fix my problem.

For example, when I have := in my text file, it prints colon, and then shows an error message saying: "; cannot follow : (colon).", whereas it should print "assign".

Here is my full code:

#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

int main(int argc, char** argv)
{
    FILE *fp;
    int c, check, reti_d, reti_l;

    regex_t digit, letter;
    reti_d = regcomp(&digit, "[0-9]", 0);
    reti_l = regcomp(&letter, "[a-zA-Z]", 0);

    if (reti_d || reti_l)
    {
        fprintf(stderr, "Couldn't compile the regular expression(s).\n");
        exit(1);
    }

    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s filename.txt\n", argv[0]);
        exit(1);
    }

    if (!(fp = fopen(argv[1], "r")))
    {
        perror("Error opening file!\n");
        exit(1);
    }

    while ((c = fgetc(fp)) != EOF)
    {
        char regdtest[1];
        char regltest[1];
        regdtest[0] = (char)c;
        reti_d = regexec(&digit, regdtest, 0, NULL, 0);
        reti_l = regexec(&letter, regltest, 0, NULL, 0);

        switch (c)
        {
            case '(': printf("lperen "); break;
            case ')': printf("rparen "); break;
            case '+': printf("plus "); break;
            case '-': printf("minus "); break;
            case '*': printf("times "); break;
        }

        if (c == ':')
        {
            if (c++ == '=')
                printf("assign ");
            else printf("\n%c cannot follow : (colon).\n", (char)c);
        }

        if (c == '/')
        {
            if (++c == '/' || ++c == '*')
            {
                while (c != '\n' || (c == '*' && ++c == '/'))
                    c++;
            }
            else printf("div ");
        }

        if (c == '.')
        {
            regdtest[0] = (char)++c;
            reti_d = regexec(&digit, regdtest, 0, NULL, 0);

            if (!reti_d)
            {
                printf("number ");
            }
            else printf("\n. (dot) should be followed by digits.\n");
        }

        if (!reti_d)
        {
            while (!reti_d)
            {
                regdtest[0] = (char)c;
                reti_d = regexec(&digit, regdtest, 0, NULL, 0);
            }

            printf("number ");
        }

        if (!reti_l)
        {
            int i, j = 0;
            char read[5], write[6];
            read[i] = write[j] = (char)c;

            while(!reti_d || !reti_l)
            {
                c++;
                i++;
                j++;

                if (i >= 5)
                    i = 0;
                if (j >= 6)
                    j = 0;

                read[i] = write[j] = (char)c;
                if (strcmp(read, "read") == 0)
                    printf("read ");
                else printf("id ");

                if (strcmp(write, "write") == 0)
                    printf("write ");
                else printf("id ");

                regdtest[0] = (char)c;
                regltest[0] = (char)c;
                reti_d = regexec(&digit, regdtest, 0, NULL, 0);
                reti_l = regexec(&letter, regltest, 0, NULL, 0);
            }

            printf("letter ");
        }

    }

    fclose(fp);
    return 0;
}

2 Answers2

1

You need to get the 2nd character by calling fgetc() once more.

pmg
  • 106,608
  • 13
  • 126
  • 198
  • You mean at every place that I have the ++ operator, I need to change to fgetc() function call? –  Mar 16 '14 at 21:37
  • Sort of. The easiest way, I think, is to have two variables: `c1` and `c2`. After reading `c1`, if you decide you need the following character, read `c2` and base your logic from there. – pmg Mar 16 '14 at 21:40
  • 2
    `c++` means to increment the value of `c`. Your variable `c` doesn't have a "history memory", it knows nothing of files or from whence it came. To get another character from the file you have to actually tell the compiler that you want to get a character from the file, e.g. `fgetc`. – M.M Mar 16 '14 at 21:57
0

As @pmg suggested, replace ++c with fgetc().

Below is a reworked if (c == '/') section. The various syntax errors path were not completely coded and the below may need additional cod to deal with unexpected paths. Remember than any fgetc() may result in the EOF condition. Also up to 1 ungetc() may be executed between fgetc() calls to undo.

if (c == '/') {
  c = fgetc(fp);
  if (c == '/') {
    c = fgetc(fp);
    if (c == '*') {
      while (c = fgetc(fp) != '\n' && c != EOF) {
        if (c == '*') {
          c = fgetc(fp);
          if (c == '/') break;
          ungetc(c, fp);
        }
      }
      printf("div ");
    }
    else TBD();
  } else ...
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256