From ad31ff953bde645086a2a35b058524b7002ff2b1 Mon Sep 17 00:00:00 2001 From: zlg Date: Wed, 6 Feb 2013 01:23:47 -0600 Subject: First crack at 1-24 Committing before I try something different. --- 1-24_syntax-checker.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 1-24_syntax-checker.c diff --git a/1-24_syntax-checker.c b/1-24_syntax-checker.c new file mode 100644 index 0000000..f56e4f7 --- /dev/null +++ b/1-24_syntax-checker.c @@ -0,0 +1,151 @@ +#include + +/* The C Programming Language: 2nd Edition + * 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.)" + * + * Proksima from Freenode's ##c helped me understand full generality where + * Ixquick, Wikipedia, and StackOverflow all failed: a program that has full + * generality handles all use cases. In this case, my program should report no + * errors from a well formed C source file, and return correct errors for every + * non-valid C source file. + * + * I can tackle this one the same way I tackled the previous exercise: with a + * FSM. The trick is in catching the mismatched levels. + */ + +/* Create our nestable counts. These keep track of each type of syntax + * character. */ +#define PARENS 0 +#define BRACKETS 1 +#define BRACES 2 + +/* Create our states, which tell the parser what's going on. INSQ, INDQ, and + * INCM are much larger so it's easier to tell what's what. If I were better + * versed in binary operations, this could use less RAM. I intend to revisit + * this later on. */ +#define OUT 0 +#define INPR 1 +#define INBK 2 +#define INBC 3 +#define INSQ 100 +#define INDQ 1000 +#define INCM 10000 + +char c; +int counts[3]; +int state, i, linenr; + +int main() { + for (i = 0; i < 3; ++i) { + counts[i] = 0; + } + + state = OUT; + linenr = 1; + // Begin streaming! + while ((c = getchar()) != EOF) { + if (c == '\n') { + linenr += 1; + if (state >= INSQ) { + break; + } + } + if (c == '(') { + counts[PARENS] += 1; + state += INPR; + } + if (c == ')') { + counts[PARENS] -= 1; + state -= INPR; + if (counts[PARENS] < 0) { + break; + } + } + if (c == '[') { + counts[BRACKETS] += 1; + state += INBK; + } + if (c == ']') { + counts[BRACKETS] -= 1; + state -= INBK; + if (counts[BRACKETS] < 0) { + break; + } + } + if (c == '{') { + counts[BRACES] += 1; + state += INBC; + } + if (c == '}') { + counts[BRACES] -= 1; + state -= INBC; + if (counts[BRACES] < 0) { + break; + } + } + if (c == '"' && state > INDQ) { + state -= INDQ; + if (state < 0) { + break; + } + } + if (c == '"' && state < INSQ) { + state += INDQ; + if (state >= (INDQ * 2)) { + break; + } + } + if (c == '\'' && state > INSQ && state < INDQ) { + state -= INSQ; + if (state < 0) { + break; + } + } + if (c == '\'' && state < INSQ) { + state += INSQ; + if (state >= (INSQ * 2)) { + break; + } + } + } + + if (state != 0) { + printf("SYNTAX ERROR: "); + + if (state >= INSQ && state < INDQ) { + printf("Unclosed single quote on line %d!\n", linenr); + return 1; + } + if (counts[PARENS] > 0) { + printf("Unclosed parenthesis on line %d!\n", linenr); + return 1; + } + if (counts[PARENS] < 0) { + printf("Too many close parentheses on line %d!\n", linenr); + return 1; + } + if (counts[BRACKETS] > 0) { + printf("Unclosed brackets on line %d!\n", linenr); + return 1; + } + if (counts[BRACKETS] < 0) { + printf("Too many close brackets on line %d!\n", linenr); + return 1; + } + if (counts[BRACES] > 0) { + printf("Unclosed braces on line %d!\n", linenr); + return 1; + } + if (counts[BRACES] < 0) { + printf("Too many close braces on line %d!\n", linenr); + return 1; + } + } + + printf("All clean.\n"); + return 0; +} -- cgit v1.2.3-70-g09d2 ;id=3ec2a2902caaf3e70deea650425339299af5d821&follow=1'>Catch when an invalid list filter is passedzlg4-3/+24 2018-10-12cli: Add zero-game import/export messageszlg2-11/+18 2018-10-10Bump to 0.3beta1 for PyPIzlg1-1/+1 2018-10-10Move tests and data to dedicated directoryzlg7-10/+26 2018-10-10cli: Add "export" commandzlg2-5/+54 2018-10-10cli: Add "import" commandzlg5-1/+76 2018-10-09Bump to 0.3alpha6 for PyPIzlg1-1/+1 2018-10-09cli: Add "notes" commandzlg2-4/+74 2018-10-09update_game: ensure notes are also savedzlg1-2/+2 2018-10-09cli: add 'update' commandzlg3-20/+92 2018-10-06cli: Add "delete" commandzlg2-0/+19 2018-10-06Remove ID field from DBzlg3-38/+46 2018-10-06cli: change "Status" heading to "Progress"zlg2-36/+40 2018-09-29Bump to 0.3alpha5 for PyPIzlg1-1/+1 2018-09-29cli: Add pretty printing to 'list' commandzlg3-17/+107 2018-09-08setup.py: Bump to alpha4 for PyPIzlg1-1/+1 2018-09-08cli: add '--raw' option to list commandzlg2-9/+45 2018-09-08Add remaining filters to vgstash packagezlg1-2/+11 2018-09-04Update LICENSE to match setup.pyzlg1-80/+67 2018-09-03Branch off from master with pytest, tox, clickzlg16-778/+779 2018-03-18Flesh out filter types and ownership statuszlg3-82/+144 2018-03-18README.mdown: break line correctlyzlg1-1/+1 2018-03-18add 'playlog' list filterzlg2-2/+9 2018-03-13Update helpers a bitzlg1-2/+9 2018-03-13Make VGSTASH_DB_LOCATION point to a filezlg2-21/+20 2016-11-18Remove settings from helpers.shZe Libertine Gamer1-5/+0 2016-11-15Correct phrasing in README.Ze Libertine Gamer1-4/+4 2016-11-13DerpZe Libertine Gamer1-0/+1 2016-11-03Improve error handling in shell scriptsZe Libertine Gamer4-3/+23 2016-10-24Correct run_again, add recursionZe Libertine Gamer1-0/+4 2016-10-21Add quotes to correct behavior for arglistZe Libertine Gamer1-1/+1 2016-10-14updater.sh: add recursion, error handlingZe Libertine Gamer1-43/+101 2016-10-14Correct pipe-handling behaviorZe Libertine Gamer1-1/+9 2016-10-12Clarify a method to move between platformsZe Libertine Gamer1-2/+5