/* * Written by Tomas Dosoudil * This file is distributed under BSD-style license. * * * LL(1) grammar * A -> numberB | ..C * B -> e | ,A | ..D * C -> numberE * D -> numberE | E * E -> ,A | e * * Default value of 'from' and 'to' in struct LinkedList is -1. Possible values are: * X 'from' is set and 'to' is -1 -> Show one item where number of item is 'from' * X.. 'from' is set and 'to' is 0 -> Show range from 'from' to end * ..X 'from' is 0 and 'to' is set -> Show range from first item to 'to' * X..X both is 0 -> From first item to last */ #include #include #include #include #include #include "input_parser.h" #define DEBUG 0 #define MAX_STRING_LENGTH 100 /* max length of string */ #define POINT(c) ((c) == '.') #define COMMA(c) ((c) == ',') #define NUMBER(c) (isdigit(c)) #define InputError(c) (printf("Parser error: Invalid syntax (%s)\n", symbName[c])) /* acceptable symbols */ typedef enum { POINT, /* . */ NUMBER, /* 0-9 */ COMMA, /* , */ EOI, /* end of input */ ERRIN = -1 /* error of input */ } LexSymbol; /* name of acceptable symbols */ static char *symbName[] = { "point", "number", "comma", "eoi" }; static LinkedList *newNode; /* new item */ static LinkedList *tail; /* tail of ll */ static LexSymbol lexSymb; /* lexical symbol */ static int number; /* number from input string */ static char *input; /* input string */ static int minimalFrom; /* smallest number which can be in 'from' */ static int ReadInputSymbol(void); static int GrammarA(void); static int GrammarB(void); static int GrammarC(void); static int GrammarD(void); static int GrammarE(void); static int CommitNode(void); static int NodeValidation(LinkedList*); /* ve finalni verzi nebude ani main() */ #if DEBUG int main(int argc, char *argv[]) { LinkedList *r; int counter; if (argc == 1) { return 1; } r = GetLinkedList(argv[1], 1); if (r == NULL) { printf("stoped in main()\n"); return 1; } counter = 0; do { printf("node %2d: ", counter); counter++; printf("%d",r->from); if (r->to != -1) printf("..%d\n", r->to); else printf("\n"); } while ((r = r->next)); return 0; } #endif /* * function that returns pointer to linked list * min - Minimal number value which can be in from. Pages are counting from 0 * but tuples from 1. */ LinkedList* GetLinkedList(char *arg, int min) { int i; LinkedList *head; minimalFrom = min; /* * validate input. only points, commas and numbers are valid input * i will find invalid characters in grammar too but it will be larger * overhead than there. */ i = 0; while (arg[i]) { if (!(POINT(arg[i]) || COMMA(arg[i]) || NUMBER(arg[i]))) { fprintf(stderr, "Parser error: Invalid input '%c'\n", arg[i]); return NULL; } i++; } /* without input */ if (i == 0) { fprintf(stderr, "Parser error: No input\n"); return NULL; } /* check maximal length */ if (MAX_STRING_LENGTH < i) { fprintf(stderr, "Parser error: Max length of argument is %d\n", MAX_STRING_LENGTH); return NULL; } input = arg; newNode = AllocateNewNode(); if (newNode == NULL) return NULL; head = newNode; tail = NULL; if (GrammarA() == -1) { FreeLinkedList(&head); } return head; } /* * read first symbol from input */ static int ReadInputSymbol(void) { char character; /* first character in word */ character = *input; /* * lexical symbol is POINT */ if (POINT(character)) { input++; character = *input; /* second point must follow */ if (!POINT(character)) { fprintf(stderr, "Parser error: Use '..' in range\n"); return ERRIN; } lexSymb = POINT; input++; } /* * lexical symbol is COMMA */ else if (COMMA(character)) { if (COMMA(*(input + 1))) { fprintf(stderr, "Parser error: Invalid syntax ',,'\n"); return ERRIN; } lexSymb = COMMA; input++; } /* * lexical symbol is NUMBER */ else if (NUMBER(character)) { /* * strtol reads numerals and return number * input pointing to first non numeral character */ number = (int) strtol(input, &input, 10); lexSymb = NUMBER; } /* * error - comma at the end */ else { if (COMMA(*(input - 1))) { fprintf(stderr, "Parser error: Remove ',' at the end\n"); return ERRIN; } lexSymb = EOI; input++; } return 0; } /* * syntax validation */ static int GrammarA(void) { if (ReadInputSymbol()) return ERRIN; switch (lexSymb) { case NUMBER: newNode->from = number; return GrammarB(); case POINT: newNode->from = minimalFrom; /* minimal value in 'from' */ return GrammarC(); default: InputError(lexSymb); return ERRIN; } } static int GrammarB(void) { if (ReadInputSymbol()) return ERRIN; switch (lexSymb) { case COMMA: if (CommitNode() == ERRIN) return ERRIN; newNode = AllocateNewNode(); if (newNode == NULL) return ERRIN; return GrammarA(); case POINT: return GrammarD(); case EOI: return CommitNode(); default: InputError(lexSymb); return ERRIN; } } static int GrammarC(void) { if (ReadInputSymbol()) return ERRIN; switch (lexSymb) { case NUMBER: newNode->to = number; return GrammarE(); default: InputError(lexSymb); return ERRIN; } } static int GrammarD(void) { if (ReadInputSymbol()) return ERRIN; switch (lexSymb) { case NUMBER: newNode->to = number; return GrammarE(); case COMMA: newNode->to = 0; /* to in range must be 0 and front of allocate */ if (CommitNode() == ERRIN) return ERRIN; newNode = AllocateNewNode(); if (newNode == NULL) return ERRIN; return GrammarA(); case EOI: newNode->to = 0; return CommitNode(); default: InputError(lexSymb); return ERRIN; } } static int GrammarE(void) { if (ReadInputSymbol()) return ERRIN; switch (lexSymb) { case COMMA: if (CommitNode() == ERRIN) return ERRIN; newNode = AllocateNewNode(); if (newNode == NULL) return ERRIN; return GrammarA(); case EOI: return CommitNode(); default: InputError(lexSymb); return ERRIN; } } /* * f makes list */ static int CommitNode(void) { if (NodeValidation(newNode) == -1) return -1; if (tail == NULL) { tail = newNode; } else { tail->next = newNode; tail = newNode; } return 0; } /* * makes and returns allocated structure LinkedList */ LinkedList* AllocateNewNode(void) { LinkedList *list; list = (LinkedList*) malloc(sizeof(LinkedList)); if (list == NULL) { perror("Parser error"); return NULL; } list->next = NULL; list->from = -1; list->to = -1; return list; } /* * function orders values * from smaller to greater, except to = 0 where 0 means to end * unentered value is -1 */ static int NodeValidation(LinkedList *node) { int num; /* array starts from 0 */ if (node->from > 0) ;//node->from--; if (node->to > 0) ;//node->to--; if ((node->from > node->to) && (node->to != 0) && (node->to != -1)) { num = node->from; node->from = node->to; node->to = num; } if (node->from < minimalFrom) { fprintf(stderr, "Parser error: Input value is too small (%d) you must use (%d)\n", node->from, minimalFrom); return -1; } return 0; } /* if error occurred clean memory and set head to NULL*/ void FreeLinkedList(LinkedList **head) { LinkedList *node; while (*head != NULL) { node = *head; *head = (*head)->next; free(node); } }