I'm done writing this exercise:
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.)
I wrote the code based on automata theory and using stack for checking parantheses, braces and brackets ( 3 functions).
Automata theory: (sorry for the language on the picture)
Basicaly Q0 is the initial state,
Q1, Q2, Q3 are the comment states.
Q4, Q5, Q6, Q7 are the single quote related states,
Q8 and Q9 are constant related states.
(ostalo = rest, zvjezdica = *, apostrof = ', navodnik = "), but you get the main idea.
Some may say it's written on a preety low level, but i like to keep it like this cause it's preety simple to write the code by looking the picture.
So if there's any way to improve this code, let me know, i think it's preety much everything the exercise asks for.
I appreciate any feedback.
Code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 1024
/* push, pop, check function */
char stack[MAX_SIZE];
int stack_counter=0;
int push(char c) /* pushes character to top of the stack */
{
if(stack_counter==1024) return 0;
stack[stack_counter++]=c;
return 1;
}
int pop() /* decrements stack_counter */
{
if(stack_counter<0) return 0;
stack_counter--;
return 1;
}
int check (char c)
{
char tmp;
switch(c)
{
case '(':
case '[':
case '{':
if((tmp=push(c)==0)) return 0;
break;
case ')':
tmp=pop();
if(tmp==0) return 0;
if(stack[stack_counter]!='(') return 0;
break;
case ']':
tmp=pop();
if(tmp==0) return 0;
if(stack[stack_counter]!='[') return 0;
break;
case '}':
tmp=pop();
if(tmp==0) return 0;
if(stack[stack_counter]!='{') return 0;
break;
}
return 1;
}
int main(int argc, char *argv[])
{
int c;
enum states { normal,
comment_entry, comment, comment_exit,
squote, squote_escape, squote2, squote3,
dquote, dquote_escape };
int line=1;
int state=normal;
int x=0;
/*
FILE *f;
f = fopen("zad90.c", "r");
if (f == NULL) return 1;
*/
/*while((c=fgetc(f))!=EOF)*/
while((c=getchar())!=EOF)
{
if(state==normal && c=='/') { state = comment_entry; }
else if(state==normal && c=='"') { state = dquote; }
else if(state==normal && c=='\'') { state = squote; }
else if(state==normal) { if((check(c))==0) printf("Line %d: Mismatching %c\n", line, c); }
else if(state==comment_entry && c=='*') { state = comment; }
else if(state==comment_entry && c=='/') { }
else if(state==comment_entry) { state = normal; if((check(c))==0) printf("Line %d: Mismatching %c\n", line, c); } /* neccesary to check braces here aswell */
else if(state==comment && c=='*') { state = comment_exit; }
else if(state==comment) {}
else if(state==comment_exit && c=='*') {}
else if(state==comment_exit && c=='/') { state = normal; }
else if(state==comment_exit) { state = comment; }
else if(state==dquote && c=='"') { state = normal; }
else if(state==dquote && c=='\\') { state = dquote_escape; }
else if(state==dquote) { }
else if(state==dquote_escape) { state = dquote; }
else if(state==squote && c=='\'') { state = normal; printf("Line %d: Contant not properly closed.\n", line); }
else if(state==squote && c=='\\') { state = squote_escape; }
else if(state==squote) { state = squote2; }
else if(state==squote_escape) { state = squote2; }
else if(state==squote2 && c=='\'') { state = normal; }
else if(state==squote2) { state = squote3; printf("Line %d: Contant not properly closed.\n", line); }
else if(state==squote3 && c=='\'') { state = normal; }
if(c=='\n') line++;
}
for(x=0; x<stack_counter; x++)
printf("Mismatching %c\n", stack[x]);
switch(state)
{
case comment:
case comment_exit:
printf("Code ends inside a comment.\n"); break;
case dquote:
case dquote_escape:
printf("Code ends inside \".\n"); break;
case squote:
case squote_escape:
case squote2:
printf("Code ends inside '.\n"); break;
default: printf("Code has no syntactic errors.\n"); break;
}
printf("Press any key to continue");
getchar();
return 0;
}