diff --git a/assignment1/problem3/Makefile b/assignment1/problem3/Makefile new file mode 100644 index 0000000..a96763e --- /dev/null +++ b/assignment1/problem3/Makefile @@ -0,0 +1,5 @@ +EXEC = uncompress +SRC = $(wildcard *.c) + +$(EXEC): $(SRC) + gcc -o $@ $^ -Wall diff --git a/assignment1/problem3/stack.c b/assignment1/problem3/stack.c new file mode 100644 index 0000000..aa94f90 --- /dev/null +++ b/assignment1/problem3/stack.c @@ -0,0 +1,123 @@ +/* + * Author: Walter + * Student ID: 1930006025 + * Assignment_1_Problem_3 + * Stack, with functioin automaticlly increase the size + */ + +#include +#include +#include +#include + +#include + +#include "stack.h" + + +bool CreateStack(Stack *stack, int size) { + /* check */ + assert(size > 0); + + /* memory allocate */ + stack->data = (ASTNode **)malloc(sizeof(ASTNode *) * size); + if (stack->data == NULL) { + return false; + } + + /* init attribute */ + stack->top = -1; + stack->size = size; + + return true; +} + +bool IsEmpty(Stack *stack) { + /* if empty, stack->top = -1 */ + return stack->top < 0; +} + +bool IsFull(Stack *stack) { + /* if full, stack->top = stack->size - 1 */ + return stack->top == stack->size - 1; +} + +bool Top(Stack *stack, ASTNode **x) { + /* check empty */ + if (IsEmpty(stack)) { + return false; + } + + /* get top */ + *x = stack->data[stack->top]; + + return true; +} + +bool Push(Stack *stack, ASTNode *x) { + /* check, enlarge stack */ + if (IsFull(stack)) { + Stack newStack; + + /* create new stack, with 2 bigger size */ + CreateStack(&newStack, stack->size * 2); + + /* copy data */ + memcpy(newStack.data, stack->data, stack->size * sizeof(ASTNode *)); + newStack.top = stack->top; + + /* delete old stack */ + DestroyStack(stack); + + /* set new stack */ + *stack = newStack; + } + + /* push */ + stack->data[++stack->top] = x; + + return true; +} + +bool Pop(Stack *stack, ASTNode **x) { + /* check */ + if (IsEmpty(stack)) { + return false; + } + + /* get x, and top - 1 */ + *x = stack->data[stack->top--]; + return true; +} + +void DisplayStack(Stack *stack) { + ASTNode **top_p = stack->data + stack->top; + + /* print the top pointer hint */ + printf("top --> "); + + /* loop for stack data */ + for (; top_p >= stack->data; top_p--) { + + /* print top --> hint */ + if (top_p != stack->data + stack->top) { + printf(" "); + } + + printf("| %p |\n", top_p); + } + + /* print top --> hint */ + if (top_p != stack->data + stack->top) { + printf(" "); + } + + printf("+--------------+\n"); +} + +void DestroyStack(Stack *stack) { + free(stack->data); + stack->data = NULL; + stack->size = 0; + stack->top = -1; +} diff --git a/assignment1/problem3/stack.h b/assignment1/problem3/stack.h new file mode 100644 index 0000000..e51cfd6 --- /dev/null +++ b/assignment1/problem3/stack.h @@ -0,0 +1,41 @@ +#ifndef MY_STACK_H +#define MY_STACK_H + +/* + * Author: Walter + * Student ID: 1930006025 + * Assignment_1_Problem_3 + * Stack, with functioin automaticlly increase the size + */ + +#include + +#include "struct.h" + +#define DEFAULT_STACK_SIZE 16 + +/* create an stack, size will automaticlly increase */ +bool CreateStack(Stack *stack, int size); + +/* check a stack whether it contains data */ +bool IsEmpty(Stack *stack); + +/* check full of stack */ +bool IsFull(Stack *stack); + +/* get the top value of a stack */ +bool Top(Stack *stack, ASTNode **x); + +/* add a value to stack */ +bool Push(Stack *stack, ASTNode *x); + +/* delete a value from stack */ +bool Pop(Stack *stack, ASTNode **x); + +/* print the stack */ +void DisplayStack(Stack *stack); + +/* delete a stack */ +void DestroyStack(Stack *stack); + +#endif diff --git a/assignment1/problem3/struct.h b/assignment1/problem3/struct.h new file mode 100644 index 0000000..b3e7908 --- /dev/null +++ b/assignment1/problem3/struct.h @@ -0,0 +1,74 @@ +/* + * Author: Walter + * Student ID: 1930006025 + * Assignment_1_Problem_3 + * the shared data structure + */ + +#ifndef MY_STRUCT_H +#define MY_STRUCT_H + +#include +#include + + +/* Used for AST Node's string */ +typedef struct ASTString_str { + char *string; + + /* the start index */ + size_t start; + + /* the end index */ + size_t end; + +} ASTString; + +/* AST Node structure, describe in ./README.md */ +typedef struct ASTNode_str { + + /* 1: string, 2: left (, 3: right ) */ + char type; + + /* valid when type==2 */ + unsigned int repeat; + + /* valid when type==1 */ + ASTString string; + + /* next node */ + struct ASTNode_str *next; + + /* child node */ + struct ASTNode_str *child; +} ASTNode; + +/* struct for stack */ +typedef struct Stack_str { + /* the size of stack */ + int size; + /* top index, empty is -1 */ + int top; + /* data */ + ASTNode **data; +} Stack; + +/* AST Scanner struct */ +typedef struct ASTScanner_str { + /* pointer to string, string will not be modified */ + char *string; + + size_t length; + size_t current_index; +} ASTScanner; + +/* AST Tree structure */ +typedef struct ASTTree_str { + ASTNode *root; + ASTNode *currNode; + Stack stack; + size_t max; + size_t count; +} ASTTree; + +#endif diff --git a/assignment1/problem3/test_main.c b/assignment1/problem3/test_main.c new file mode 100644 index 0000000..0bc78f5 --- /dev/null +++ b/assignment1/problem3/test_main.c @@ -0,0 +1,16 @@ +#include +#include + +#include "uncompress.h" + +int main() { + Uncompress(NULL, stdout); + Uncompress("", stdout); + Uncompress("abc", stdout); + Uncompress("a1(b)c", stdout); + Uncompress("a11(c)d", stdout); + Uncompress("3(a)2(bc)", stdout); + Uncompress("3(a2(c))", stdout); + Uncompress("2(abb3(cd))ef", stdout); + return 0; +} diff --git a/assignment1/problem3/uncompress.c b/assignment1/problem3/uncompress.c new file mode 100644 index 0000000..d92ff0e --- /dev/null +++ b/assignment1/problem3/uncompress.c @@ -0,0 +1,329 @@ +#include +#include +#include +#include +#include + +#include "uncompress.h" +#include "stack.h" + +ASTScanner *CreateASTScanner(char *string) { + /* Special case define in pdf */ + if (string == NULL) { + string = "NULL"; + } + + /* allocate scanner memory space */ + ASTScanner *scanner = (ASTScanner *)malloc(sizeof(ASTScanner)); + if (scanner == NULL) { + fprintf(stderr, "allocate scanner memory failed\n"); + exit(1); + } + + /* init values */ + scanner->string = string; + scanner->length = strlen(string); + scanner->current_index = 0; + + return scanner; +} + +char ASTScan(ASTScanner *scanner, ASTNode **ret_node) { + size_t i; + + /* return if it reached the end */ + if (scanner->current_index == scanner->length) { + *ret_node = NULL; + return 0; + } + + /* allocate memory space */ + ASTNode *node = (ASTNode *)calloc(1, sizeof(ASTNode)); + if (node == NULL) { + fprintf(stderr, "allocate ASTNode memory failed\n"); + exit(1); + } + + /* read until end or '(' or ')', + * after the loop, i point after '(' or ')' */ + i = scanner->current_index; + while (i < scanner->length) { + if (scanner->string[i]=='(' || scanner->string[i] == ')') { + i++; + break; + } + i++; + } + + /* if read ( */ + if (scanner->string[i-1] == '(') { + node->type = 2; + + /* check is there is any number before ( */ + if (i-1 == 0) { + fprintf(stderr, "Syntax error: invailed value of repeat at begining\n"); + return 1; + } + if (!IsNumber(scanner->string[i-2])) { + fprintf(stderr, "Syntax error: invailed value of repeat at index %ld\n", i-1); + return 1; + } + + /* get number and the string before the number */ + node->repeat = GetNumber(scanner->string, scanner->current_index, i-1, &node->string); + /* if the string exists */ + if (node->string.string) { + /* change type to 1 */ + node->type = 1; + node->repeat = 0; + i = node->string.end; + } + + /* if read ) */ + } else if (scanner->string[i-1] == ')') { + node->type = 3; + + /* if there are string before ) */ + if (i-1 != scanner->current_index) { + + /* change type to 1 */ + node->type = 1; + node->string.string = scanner->string; + node->string.start = scanner->current_index; + node->string.end = i-1; + i = i - 1; + } + + /* until the end is a string */ + } else { + node->type = 1; + node->string.string = scanner->string; + node->string.start = scanner->current_index; + node->string.end = i; + } + + /* set current_index */ + scanner->current_index = i; + + /* set return node */ + *ret_node = node; + + return 0; +} + +unsigned int GetNumber(char *string, size_t start, size_t end, ASTString *other_string) { + unsigned int result = 0; + size_t index = end - 1; + + /* convert string to integer */ + for (unsigned count = 1; IsNumber(string[index]); index--, count++) { + result = result + (string[index] - '0') * Power(10, count); + } + + /* if there is a string before the number, + * set to other_string */ + if (index + 1 != start) { + other_string->string = string; + other_string->start = start; + other_string->end = index + 1; + } + + return result; +} + +bool IsNumber(const char c) { + return c >= '0' && c <= '9'; +} + +unsigned int Power(int x, int y) { + unsigned int result = 1; + for (int i=1; itype, + currNode->next, + currNode->child, + currNode->repeat, + currNode->string.start, + currNode->string.end); + + if (currNode->type == 2) { + /* recursion to child */ + DEBUG_NODE(currNode->child); + } + + /* move forward */ + currNode = currNode->next; + } +} + +void DestroyASTTree(ASTTree *tree) { + ASTNode *currNode, *delNode; + + /* push root node into stack */ + Push(&tree->stack, tree->root); + + /* loop to destroy all node */ + while (!IsEmpty(&tree->stack)) { + + /* get node from stack */ + Pop(&tree->stack, &currNode); + + while (currNode) { + + if (currNode->type == 2) { + /* store child node into stack */ + Push(&tree->stack, currNode->child); + } + + /* delete node */ + delNode = currNode; + currNode = currNode->next; + free(delNode); + } + } + + /* finally do not forget to free everything */ + DestroyStack(&tree->stack); + free(tree); +} + +ASTTree *CreateASTTree() { + /* allocate memory */ + ASTTree *tree = (ASTTree *)calloc(1, sizeof(ASTTree)); + if (tree == NULL) { + fprintf(stderr, "Can not allocate AST Tree memory\n"); + exit(1); + } + + /* create stack with tree */ + CreateStack(&tree->stack, DEFAULT_STACK_SIZE); + + return tree; +} + +void ASTCompileTree(ASTTree *tree, FILE *file) { + + ASTCompileNode(tree->root, file); + + /* new line at the end */ + fputc('\n', file); +} + +void ASTCompileNode(ASTNode *root, FILE *file) { + ASTNode *currNode = root; + + /* loop for node and its all next node */ + for (; currNode; currNode = currNode->next) { + + if (currNode->type == 2) { + /* repeat to compile child node */ + for (int i=0; irepeat; i++) { + /* recursion */ + ASTCompileNode(currNode->child, file); + } + + } else if (currNode->type == 1) { + /* print string */ + for (size_t i=currNode->string.start; istring.end; i++) { + fputc(currNode->string.string[i], file); + } + } + } +} + +char ASTScanAll(ASTTree *tree, ASTScanner *scanner) { + bool goback = false; + char err; + ASTNode *node = NULL, *last = NULL; + + /* scan the first (root) node */ + ASTScan(scanner, &node); + tree->root = node; + tree->max++; + last = tree->root; + + /* set last node as last type 2 node */ + if (node != NULL) { + if (node->type == 2) { + Push(&tree->stack, node); + } + } + + /* scan until end */ + while(err = ASTScan(scanner, &node), node) { + + /* raise error */ + if (err != 0) { + return err; + } + + /* set goback flag, set last node as last type 2 node */ + if (node->type == 3) { + goback = true; + Pop(&tree->stack, &last); + free(node); + continue; + /* uf node type is 2, record in stack */ + } else if (node->type == 2) { + Push(&tree->stack, node); + } + + /* connect to last node */ + if (last->type == 1) { + last->next = node; + } else if (last->type == 2) { + if (goback) { + last->next = node; + goback = false; + } else { + last->child = node; + } + } + + /* record last node, increase max */ + last = node; + tree->max++; + } + return 0; +} + +void Uncompress(char *string, FILE *file) { + char err; + + /* create scanner and AST tree */ + ASTScanner *scanner = CreateASTScanner(string); + ASTTree *tree = CreateASTTree(); + + /* scan all token into tree */ + err = ASTScanAll(tree, scanner); + if (err != 0) { + fprintf(stderr, "EXITED"); + exit(1); + } + + /* + printf("---debug---\n"); + DEBUG_NODE(tree->root); + printf("---debug---\n"); + */ + + /* compile */ + ASTCompileTree(tree, file); + + /* free memory */ + DestroyASTTree(tree); + DestroyASTScanner(scanner); +} + +void DestroyASTScanner(ASTScanner *scanner) { + free(scanner); +} diff --git a/assignment1/problem3/uncompress.h b/assignment1/problem3/uncompress.h new file mode 100644 index 0000000..dcec38b --- /dev/null +++ b/assignment1/problem3/uncompress.h @@ -0,0 +1,49 @@ +#ifndef UNCOMPRESS +#define UNCOMPRESS + +#include +#include +#include + +#include "struct.h" + +/* return a pointer of a new scanner, string will not be copied */ +ASTScanner *CreateASTScanner(char *string); + +/* return a pointer of a new Tree */ +ASTTree *CreateASTTree(); + +/* return a pointer of a token, return NULL if reached the end */ +char ASTScan(ASTScanner *scanner, ASTNode **ret_node); + +/* scan all token from scanner into tree */ +char ASTScanAll(ASTTree *tree, ASTScanner *scanner); + +/* return the number before a string with index */ +unsigned int GetNumber(char *string, size_t start, size_t end, ASTString *other_string); + +/* Useful function to check whether a char is a number */ +bool IsNumber(const char c); + +/* math calc, Power(10, 4) return 10000 */ +unsigned int Power(int x, int y); + +/* destroy AST scanner, memory of string will not be free */ +void DestroyASTScanner(ASTScanner *scanner); + +/* Destroy AST Tree */ +void DestroyASTTree(ASTTree *tree); + +/* Display debug information to screen from root node */ +void DEBUG_NODE(ASTNode *root); + +/* Compile the tree to file stream */ +void ASTCompileTree(ASTTree *tree, FILE *file); + +/* Compile node and its all next node to file stream */ +void ASTCompileNode(ASTNode *root, FILE *file); + +/* A short cut function, directly uncompress the raw string to file stream */ +void Uncompress(char *string, FILE *file); + +#endif