├── .gitignore ├── README.mkd ├── project2 ├── pet │ ├── README.mkd │ ├── demo │ │ ├── Makefile │ │ └── main.c │ └── modules │ │ └── pet │ │ ├── cat.c │ │ ├── dog.c │ │ ├── make.inc │ │ └── pet.h └── reusable_modules │ ├── README.mkd │ ├── demo1 │ ├── Makefile │ ├── list_item.h │ └── main.c │ ├── demo2 │ ├── Makefile │ └── main.c │ ├── demo3 │ ├── Makefile │ ├── main.c │ └── stack_item.h │ └── modules │ ├── list │ ├── common.c │ ├── linked.c │ ├── list.h │ ├── make.inc │ └── sequential.c │ ├── point │ ├── list_item.h │ ├── make.inc │ ├── point.c │ └── point.h │ └── stack │ ├── list_item.h │ ├── make.inc │ ├── stack.c │ └── stack.h └── project3 └── generic_lists ├── Makefile ├── README.mkd ├── demo_symboltable ├── Makefile ├── STItem.h ├── list_item.h └── main.c ├── demo_template ├── Makefile └── main.c ├── demo_union ├── Makefile ├── list_item.h └── main.c ├── demo_untyped ├── Makefile └── main.c ├── demo_voidpointer ├── Makefile ├── list_item.h └── main.c └── modules ├── SymbolTable ├── SymbolTable.c ├── SymbolTable.h └── make.inc ├── list_template ├── list.h ├── list_impl.h └── make.inc ├── list_typed ├── list.c ├── list.h ├── list_types.h └── make.inc └── list_untyped ├── list.c ├── list.h └── make.inc /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .vscode 3 | demo* 4 | !demo*/ 5 | -------------------------------------------------------------------------------- /README.mkd: -------------------------------------------------------------------------------- 1 | ### k08_code 2 | 3 | Βοηθητικός κώδικας για το μάθημα [Δομές Δεδομένων και Τεχνικές Προγραμματισμού](http://cgi.di.uoa.gr/~k08/). -------------------------------------------------------------------------------- /project2/pet/README.mkd: -------------------------------------------------------------------------------- 1 | ### pet 2 | 3 | A dummy pet module with two implementations: 4 | - as cat 5 | - as dog 6 | 7 | The goal is to create the Makefile. -------------------------------------------------------------------------------- /project2/pet/demo/Makefile: -------------------------------------------------------------------------------- 1 | # fill this -------------------------------------------------------------------------------- /project2/pet/demo/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include "pet.h" 3 | 4 | 5 | int main() { 6 | // create 2 pets, make them talk 7 | 8 | Pet pet1 = PetCreate(); 9 | Pet pet2 = PetCreate(); 10 | 11 | PetTalk(pet1); 12 | PetTalk(pet2); 13 | } -------------------------------------------------------------------------------- /project2/pet/modules/pet/cat.c: -------------------------------------------------------------------------------- 1 | // implement pet as cat 2 | 3 | #include 4 | 5 | #include "pet.h" 6 | 7 | 8 | Pet PetCreate() { 9 | static double counter = 0; 10 | return counter++; // a cat is a double, return a different one every time 11 | } 12 | 13 | void PetTalk(Pet cat) { 14 | printf("cat %f says: meow\n", cat); 15 | } -------------------------------------------------------------------------------- /project2/pet/modules/pet/dog.c: -------------------------------------------------------------------------------- 1 | // implement pet as dog 2 | 3 | #include 4 | 5 | #include "pet.h" 6 | 7 | 8 | Pet PetCreate() { 9 | static int counter = 0; 10 | return counter++; // a dog is an int, return a different one every time 11 | } 12 | 13 | void PetTalk(Pet dog) { 14 | printf("dog %d says: woof\n", dog); 15 | } 16 | -------------------------------------------------------------------------------- /project2/pet/modules/pet/make.inc: -------------------------------------------------------------------------------- 1 | # fill this -------------------------------------------------------------------------------- /project2/pet/modules/pet/pet.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // An abstract pet module 4 | // Can be implemented as dog or cat. 5 | 6 | 7 | // enable this flag to implement pet as dog. 8 | // #define PET_IMPL_DOG 9 | // 10 | // Equivalently compile with: gcc -DPET_IMPL_DOG ... 11 | 12 | 13 | #ifdef PET_IMPL_DOG 14 | // implement pet as dog 15 | typedef int Pet; // dogs are ints 16 | #else 17 | // implement pet as cat 18 | typedef double Pet; // cats are doubles 19 | #endif 20 | 21 | 22 | // functions 23 | // 24 | Pet PetCreate(); 25 | void PetTalk(Pet pet); 26 | -------------------------------------------------------------------------------- /project2/reusable_modules/README.mkd: -------------------------------------------------------------------------------- 1 | 2 | ### reusable_modules 3 | 4 | #### Usage 5 | 6 | ``` 7 | cd demo1 # or demo2 or demo3 8 | make run LST_IMPL=linked 9 | make run LST_IMPL=sequential 10 | ``` 11 | 12 | #### Περιγραφή 13 | 14 | Ο κώδικας στο directory αυτό επιδεικνύει διάφορες τεχνικές οι οποίες 15 | είναι χρήσιμες για την ανάπτυξη σχετικά μεγάλων προγραμμάτων. 16 | 17 | - Περιλαμβάνται 3 modules 18 | - [list](modules/list): υλοποίηση του ADT List με 2 τρόπους: 19 | - sequential: με array 20 | - linked: συνδεδεμένη λίστα 21 | - [point](modules/point): αναπαράσταση σημείων (διανυσμάτων) n-διαστάσεων 22 | - υλοποίηση μέσω του list module 23 | - [stack](modules/stack): υλοποίηση του ADT Stack 24 | - υλοποίηση μέσω του list module 25 | 26 | - Και 3 προγράμματα που επιδεικνύουν τα modules 27 | - [demo1](demo1): απ'ευθείας χρήση μια λίστας από strings 28 | - [demo2](demo2): χρήση points (που εσωτερικά χρησιμοποιούν lists) 29 | - [demo3](demo3): χρήση stack (που εσωτερικά χρησιμοποιεί lists) 30 | 31 | - Δείχνεται πώς κάποια modules (point, stack) μπορούν να υλοποιήσουν μια δομή 32 | δεδομένων __χρησιμοποιώντας εσωτερικά ένα άλλο module__ (list). 33 | 34 | - Δείχνεται πώς __ο ίδιος κώδικας του module__ μπορεί να χρησιμοποιηθεί σε __διαφορετικά 35 | προγράμματα__ 36 | - τα modules (list, point, stack) βρίσκονται σε διαφορετικό directory από τα 37 | προγράμματα (demo1, demo2, demo3), δεν υπάρχει διπλός κώδικας. 38 | - τα modules γίνονται compile σε κάθε πρόγραμμα μέσα από το αντίστοιχο Makefile 39 | του προγράμματος 40 | - κάθε module παρέχει ένα αρχείο [make.inc](modules/list/make.inc), το όποιο γίνεται include στο [Makefile](demo1/Makefile) του προγράμματος για να ρυθμιστεί σωστά το compilation 41 | (αυτός είναι ένας από τους πολλούς τρόπους οργάνωσης σύνθετων Makefiles) 42 | - ο compiler ρυθμίζεται (παράμετρος ```-I...```) ώστε να βρίσκει 43 | τα header files στο σωστό directory. 44 | 45 | - Δείχνεται πώς η υλοποίηση ενός module μπορεί να αλλάξει εύκολα μέσω __conditional compilation__ 46 | - βλέπε [modules/list/make.inc](modules/list/make.inc) 47 | - Ανάλογα με το ```LST_IMPL``` 48 | - ρυθμίζεται να γίνει compile το αντίστοιχο .c αρχείο 49 | - δημιουργούνται τα κατάλληλα ```#define```s ώστε να λειτουργήσει 50 | το ```#ifdef``` στο modules/list.h 51 | 52 | - Δείχνεται πώς χωρίς καμία αλλαγή στον κώδικα του list module μπορούν 53 | να δημιουργηθούν λίστες διαφορετικών τύπων 54 | - demo1: λίστες από strings 55 | - point module: λίστες από double 56 | - stack module: λίστες από StItem 57 | - Η επιλογή του τύπου γίνεται από το __χρήστη του module__, δηλαδή: 58 | - για το demo1 που χρησιμοιεί strings: αρχείο [demo1/list_item.h](demo1/list_item.h) 59 | - για το point module που χρησιμοιεί double: αρχείο [modules/point/list_item.h](modules/point/list_item.h) 60 | - για το stack module που χρησιμοιεί StItem: αρχείο [modules/stack/list_item.h](modules/stack/list_item.h) 61 | - Στις δύο πρώτες περιπτώσεις, δείχνεται πώς κατάλληλες συναρτήσεις ```compare``` χρησιμοποιούνται για τον κάθε τύπο. 62 | 63 | 64 | -------------------------------------------------------------------------------- /project2/reusable_modules/demo1/Makefile: -------------------------------------------------------------------------------- 1 | # Where are our moduleS? 2 | MODULES = ../modules 3 | 4 | # Set compiler options here. 5 | # Set -I. so that include files in this directory are always found (even when compiling the modules in other dirs) 6 | # 7 | CFLAGS = -g -Wall -I. 8 | 9 | # set the name of the executable file to compile here 10 | PROGRAM = demo1 11 | 12 | # List object files needed to compile the program. 13 | OBJS = main.o 14 | 15 | # We use the list module, include its make.inc so that it can configure itself 16 | include $(MODULES)/list/make.inc 17 | 18 | 19 | # Note: normally we should list .h dependencies of all .o files so that make 20 | # BUT: things get tricky when conditional compilation is used (make does not detect changes in variables!) 21 | # Simple solution: always clean before building! (by having "clean" as a dependency) 22 | # (there are better solutions, but for our needs this one is good and simple) 23 | # 24 | $(PROGRAM): clean $(OBJS) 25 | gcc $(OBJS) -o $(PROGRAM) -lm 26 | 27 | clean: 28 | rm -f $(PROGRAM) $(OBJS) 29 | 30 | run: $(PROGRAM) 31 | ./$(PROGRAM) 32 | 33 | -------------------------------------------------------------------------------- /project2/reusable_modules/demo1/list_item.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // This file is part of demo1 4 | // 5 | // demo1 uses lists, so we need to set the LstItem properly. 6 | // For our purposes we need a list of strings, so... 7 | 8 | typedef char *LstItem; 9 | -------------------------------------------------------------------------------- /project2/reusable_modules/demo1/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "list.h" 5 | 6 | 7 | int compare_strings(char *a, char *b) { 8 | return strcmp(a, b); 9 | } 10 | 11 | int main() { 12 | // A simple demo of a list of strings 13 | 14 | LstList list = LstCreate(5); 15 | 16 | LstSet(list, 0, "Tyrion"); 17 | LstSet(list, 1, "Jaime"); 18 | LstSet(list, 2, "Cercei"); 19 | LstSet(list, 3, "Daenerys"); 20 | LstSet(list, 4, "Jon"); 21 | 22 | printf("Find Tyrion: %d\n", LstFind(list, "Tyrion", compare_strings)); 23 | printf("Find Ned: %d\n", LstFind(list, "Ned", compare_strings)); 24 | } -------------------------------------------------------------------------------- /project2/reusable_modules/demo2/Makefile: -------------------------------------------------------------------------------- 1 | # Where are our moduleS? 2 | MODULES = ../modules 3 | 4 | # Set compiler options here. 5 | # 6 | CFLAGS = -g -Wall 7 | 8 | # set the name of the executable file to compile here 9 | PROGRAM = demo2 10 | 11 | # List object files needed to compile the program. 12 | OBJS = main.o 13 | 14 | # We use the point module, include its make.inc so that it can configure itself 15 | include $(MODULES)/point/make.inc 16 | 17 | 18 | # Note: normally we should list .h dependencies of all .o files so that make 19 | # BUT: things get tricky when conditional compilation is used (make does not detect changes in variables!) 20 | # Simple solution: always clean before building! (by having "clean" as a dependency) 21 | # (there are better solutions, but for our needs this one is good and simple) 22 | # 23 | $(PROGRAM): clean $(OBJS) 24 | gcc $(OBJS) -o $(PROGRAM) -lm 25 | 26 | clean: 27 | rm -f $(PROGRAM) $(OBJS) 28 | 29 | run: $(PROGRAM) 30 | ./$(PROGRAM) 31 | 32 | -------------------------------------------------------------------------------- /project2/reusable_modules/demo2/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "point.h" 4 | 5 | // A simple demo of the point module. 6 | // 7 | // Note that the code here just uses Points. We don't know 8 | // or care whether Points internally use lists. 9 | 10 | int main() { 11 | Point a = Pnt3D(1, 2, 3); 12 | Point b = Pnt3D(-2, 3, 0); 13 | 14 | printf("a: "); PntPrint(a); printf("\n"); 15 | printf("b: "); PntPrint(b); printf("\n"); 16 | printf("compare a and a: %d\n", PntCompare(a, a)); 17 | printf("compare a and b: %d\n", PntCompare(a, b)); 18 | printf("distance: %f\n", PntDistance(a, b)); 19 | 20 | Point one = PntOne(10); 21 | Point two = PntScale(one, 2); 22 | 23 | printf("\none: "); PntPrint(one); printf("\n"); 24 | printf("two: "); PntPrint(two); printf("\n"); 25 | printf("distance: %f\n", PntDistance(one, two)); 26 | } -------------------------------------------------------------------------------- /project2/reusable_modules/demo3/Makefile: -------------------------------------------------------------------------------- 1 | # Where are our moduleS? 2 | MODULES = ../modules 3 | 4 | # Set compiler options here. 5 | # Set -I. so that include files in this directory are always found (even when compiling the modules in other dirs) 6 | # 7 | CFLAGS = -g -Wall -I. 8 | 9 | # set the name of the executable file to compile here 10 | PROGRAM = demo3 11 | 12 | # List object files needed to compile the program. 13 | OBJS = main.o 14 | 15 | # We use the stack module, include its make.inc so that it can configure itself 16 | include $(MODULES)/stack/make.inc 17 | 18 | 19 | # Note: normally we should list .h dependencies of all .o files so that make 20 | # BUT: things get tricky when conditional compilation is used (make does not detect changes in variables!) 21 | # Simple solution: always clean before building! (by having "clean" as a dependency) 22 | # (there are better solutions, but for our needs this one is good and simple) 23 | # 24 | $(PROGRAM): clean $(OBJS) 25 | gcc $(OBJS) -o $(PROGRAM) 26 | 27 | clean: 28 | rm -f $(PROGRAM) $(OBJS) 29 | 30 | run: $(PROGRAM) 31 | ./$(PROGRAM) 32 | 33 | -------------------------------------------------------------------------------- /project2/reusable_modules/demo3/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stack.h" 4 | 5 | 6 | int main() { 7 | StStack stack = StCreate(100); 8 | 9 | StInsert(stack, 5); 10 | StInsert(stack, 6); 11 | StInsert(stack, 7); 12 | 13 | printf("remove: %d", StRemove(stack)); 14 | printf(", Empty?: %d\n", StEmpty(stack)); 15 | 16 | printf("remove: %d", StRemove(stack)); 17 | printf(", Empty?: %d\n", StEmpty(stack)); 18 | 19 | printf("remove: %d", StRemove(stack)); 20 | printf(", Empty?: %d\n", StEmpty(stack)); 21 | } -------------------------------------------------------------------------------- /project2/reusable_modules/demo3/stack_item.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // This file is part of demo3 4 | // 5 | // demo3 uses stacks, so we need to set the StItem properly. 6 | // For our purposes we need a stack of ints, so... 7 | 8 | typedef int StItem; 9 | -------------------------------------------------------------------------------- /project2/reusable_modules/modules/list/common.c: -------------------------------------------------------------------------------- 1 | 2 | // functions that are common for both list implementations (so that we don't need to write them twice!) 3 | 4 | #include "list.h" 5 | 6 | 7 | // Note: For the sequential implementation both algorithms below are O(n). 8 | // But maybe for the linked implementation they are O(n^2) ??? 9 | // TODO: check this, and maybe provide separate sequential/linked implementations in the future. 10 | 11 | 12 | int LstCompare(LstList list1, LstList list2, LstCompareFunc compare) { 13 | 14 | // This should work for both implementations! If we only use Lst* 15 | // functions (instead of accessing list1/list2 directly) we should be fine. 16 | 17 | int len = LstLength(list1); 18 | if(len != LstLength(list2)) 19 | return -1; // different length, so not equal! 20 | 21 | for(int i = 0; i < len; i++) 22 | if(compare(LstGet(list1, i), LstGet(list2, i)) != 0) 23 | return -1; // different i-th elements, so not equal! 24 | 25 | return 0; // everything ok, equal! 26 | 27 | } 28 | 29 | int LstFind(LstList list, LstItem item, LstCompareFunc compare) { 30 | int len = LstLength(list); 31 | for(int i = 0; i < len; i++) 32 | if(compare(item, LstGet(list, i)) == 0) 33 | return i; // found it 34 | 35 | return -1; // it's not here 36 | } 37 | -------------------------------------------------------------------------------- /project2/reusable_modules/modules/list/linked.c: -------------------------------------------------------------------------------- 1 | 2 | // list implementation using a variable-length linked list 3 | 4 | #include 5 | #include 6 | 7 | #include "list.h" 8 | 9 | 10 | // We use a dummy node as first for every list. The whole list (LstList) is represented by the dummy node, so LstList and LstNode are the same. 11 | typedef struct lst_node *LstNode; 12 | 13 | // the actual definition of our struct 14 | struct lst_node { 15 | LstItem item; 16 | LstNode next; 17 | }; 18 | 19 | 20 | // auxiliary function to create a new node with a given next 21 | // static so that it is completely hidden from the outside world 22 | // 23 | static LstNode NewNode(LstNode next) { 24 | LstNode node = malloc(sizeof(*node)); 25 | node->next = next; 26 | return node; 27 | } 28 | 29 | 30 | LstList LstCreate(int maxlen) { 31 | return NewNode(NULL); // empty list represented by a dummy node 32 | } 33 | 34 | void LstDestroy(LstList list) { 35 | LstNode node = list; 36 | while(node != NULL) { 37 | LstNode next = node->next; // get this before free()! 38 | free(node); 39 | node = next; 40 | } 41 | } 42 | 43 | int LstLength(LstList list) { 44 | // start from the first _real_ node, count them 45 | int res = 0; 46 | for(LstNode node = list->next; node != NULL; node = node->next) 47 | res++; 48 | return res; 49 | } 50 | 51 | LstItem LstGet(LstList list, int pos) { 52 | // TODO: maybe we can do this faster? 53 | if(pos < 0 || pos >= LstLength(list)) { 54 | printf("out of bounds: %d\n", pos); 55 | exit(-1); // failure, just die 56 | } 57 | 58 | LstNode node = list->next; // start from the first _real_ node, advance pos times 59 | for(int i = 0; i < pos; i++) 60 | node = node->next; 61 | return node->item; 62 | } 63 | 64 | void LstSet(LstList list, int pos, LstItem item) { 65 | LstNode node = list; 66 | 67 | for(int i = 0; i < pos+1; i++) { // we start from the dummy, so we need pos+1 advances to reach the node 68 | if(node->next == NULL) 69 | node->next = NewNode(NULL); // the node hasn't been create it yet, do it now 70 | node = node->next; 71 | } 72 | node->item = item; 73 | } -------------------------------------------------------------------------------- /project2/reusable_modules/modules/list/list.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // A (very) simple list 4 | // 5 | // Two implementations are given: 6 | // - sequential 7 | // * constant-time Get/Set/Length 8 | // * fixed-length 9 | // - linked 10 | // * linear-time Get/Set/Length 11 | // * variable length 12 | // 13 | // To select implementation: make LST_IMPL=[sequential|linked] 14 | 15 | // The list contains items of type LstItem. It's the _user's_ job to define LstItem (not ours). 16 | // He should make sure that a "list_item.h" file is accessible by the compiler and defines LstItem 17 | // 18 | #include "list_item.h" 19 | 20 | // Types 21 | // diffent types are used for the sequential and linked implementations! 22 | 23 | #ifdef LST_IMPL_SEQUENTIAL // LST_IMPL_SEQUENTIAL is set in make.inc, when LST_IMPL=sequential is passed 24 | // types: sequential implementation 25 | typedef struct { 26 | int length; // store the length 27 | LstItem *items; // and an array of LstItems 28 | } LstList; 29 | 30 | #else 31 | // types: linked implementation 32 | typedef struct lst_node *LstList; // LstList is a pointer to "struct lst_node". This is the "handle" design, only linked.c needs to know what the struct really is! 33 | #endif 34 | 35 | typedef int (*LstCompareFunc)(LstItem a, LstItem b); // LstCompareFunc: type of functions that compare 2 LstItems 36 | 37 | 38 | // Functions 39 | // *independent* from the implementation, so that changing implementation is easy! 40 | // 41 | // creates a new list (length is only used in the sequential implementation) 42 | // 43 | LstList LstCreate(int length); 44 | 45 | // destroys a list 46 | // 47 | void LstDestroy(LstList list); 48 | 49 | // returns the length of a list 50 | // - for the sequential implementation, the length is fixed 51 | // - for the linked implementation, it's 1 + the maximum position set with LstSet 52 | // 53 | int LstLength(LstList list); 54 | 55 | // returns the pos-th element (error if out of bounds) 56 | // 57 | LstItem LstGet(LstList list, int pos); 58 | 59 | // sets the pos-th element (sequential: error if out of bounds) 60 | // 61 | void LstSet(LstList list, int pos, LstItem item); 62 | 63 | // return 0 if list1 and list2 are equal (equal length, equal elements) 64 | // compare(item1, item2) should return 0 if item1 == item2 65 | // 66 | int LstCompare(LstList list1, LstList list2, LstCompareFunc compare); 67 | 68 | // Returns the index of the first occurance of item in the list (or -1 if no occurence exists) 69 | // compare(item1, item2) should return 0 if item1 == item2 70 | // 71 | int LstFind(LstList list, LstItem item, LstCompareFunc compare); 72 | -------------------------------------------------------------------------------- /project2/reusable_modules/modules/list/make.inc: -------------------------------------------------------------------------------- 1 | # This file is part of the list module. 2 | # 3 | # Anyone who wants to use the list module should include this file in their 4 | # Makefile, so that compilation is configured properly 5 | # 6 | 7 | # Set compiler flags. -I... tells the compiler to look in our directory for 8 | # include files, so that #include "list.h" works. 9 | # 10 | CFLAGS += -I$(MODULES)/list 11 | 12 | # Always compile common.o (but we will add more .o files to be compiled below!) 13 | # 14 | OBJS += $(MODULES)/list/common.o 15 | 16 | # CONDITIONAL COMPILATION 17 | # 18 | # Use the LIST_IMPL=[linked|sequential] flag to select whether a linked or 19 | # sequential implementation of lists is used. We need to do 2 things: 20 | # 1. compile the correct implementation (linked.o OR sequential.o) 21 | # 2. set (with -D...) the correct preprocessor flag (LST_IMPL_LINKED OR 22 | # LST_IMPL_SEQUENTIAL) so that #ifdef works in the code (see list.h) 23 | # 24 | ifeq ($(LST_IMPL),linked) 25 | # linked implementation 26 | CFLAGS += -DLST_IMPL_LINKED 27 | OBJS += $(MODULES)/list/linked.o 28 | else 29 | # sequential implementation (default) 30 | CFLAGS += -DLST_IMPL_SEQUENTIAL 31 | OBJS += $(MODULES)/list/sequential.o 32 | endif 33 | -------------------------------------------------------------------------------- /project2/reusable_modules/modules/list/sequential.c: -------------------------------------------------------------------------------- 1 | 2 | // list implementation using a fixed-length array 3 | 4 | #include 5 | #include 6 | 7 | #include "list.h" 8 | 9 | 10 | LstList LstCreate(int length) { 11 | LstList list; 12 | list.items = malloc(sizeof(LstItem) * length); 13 | list.length = length; 14 | return list; 15 | } 16 | 17 | void LstDestroy(LstList list) { 18 | free(list.items); 19 | } 20 | 21 | int LstLength(LstList list) { 22 | return list.length; 23 | } 24 | 25 | LstItem LstGet(LstList list, int pos) { 26 | if(pos < 0 || pos >= list.length) { 27 | printf("out of bounds: %d\n", pos); 28 | exit(-1); // failure, just die 29 | } 30 | return list.items[pos]; 31 | } 32 | 33 | void LstSet(LstList list, int pos, LstItem item) { 34 | if(pos < 0 || pos >= list.length) { 35 | printf("out of bounds: %d\n", pos); 36 | exit(-1); // failure, just die 37 | } 38 | list.items[pos] = item; 39 | } -------------------------------------------------------------------------------- /project2/reusable_modules/modules/point/list_item.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // This file is part of the point module. 4 | // 5 | // We use lists, so we need to set the LstItem properly. 6 | // For our purposes we need a list of doubles, so... 7 | 8 | typedef double LstItem; -------------------------------------------------------------------------------- /project2/reusable_modules/modules/point/make.inc: -------------------------------------------------------------------------------- 1 | # This file is part of the point module. 2 | # 3 | # Anyone who wants to use the point module should include this file in their 4 | # Makefile, so that compilation is configured properly 5 | # 6 | 7 | # Set compiler flags. -I... tells the compiler to look in our directory for 8 | # include files, so that #include "point.h" works. 9 | # 10 | CFLAGS += -I$(MODULES)/point 11 | 12 | # We need to compile point.o 13 | # 14 | OBJS += $(MODULES)/point/point.o 15 | 16 | # We use the list module, include its make.inc so that it can configure itself. 17 | # 18 | include $(MODULES)/list/make.inc 19 | -------------------------------------------------------------------------------- /project2/reusable_modules/modules/point/point.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "point.h" 7 | 8 | // Note: this is just a demo, so no memory is freed. Ever :D 9 | 10 | 11 | 12 | Point PntOne(int n) { 13 | Point point = LstCreate(n); // lists are already implemented, life is so easy.. 14 | for(int i = 0; i < n; i++) 15 | LstSet(point, i, 1); 16 | return point; 17 | } 18 | 19 | Point Pnt2D(double x, double y) { 20 | Point point = LstCreate(2); 21 | LstSet(point, 0, x); 22 | LstSet(point, 1, y); 23 | return point; 24 | } 25 | 26 | Point Pnt3D(double x, double y, double z) { 27 | Point point = LstCreate(3); 28 | LstSet(point, 0, x); 29 | LstSet(point, 1, y); 30 | LstSet(point, 2, z); 31 | return point; 32 | } 33 | 34 | int PntGetDim(Point point) { 35 | return LstLength(point); // easy 36 | } 37 | 38 | double PntGetCoord(Point point, int i) { 39 | return LstGet(point, i); // easy 40 | } 41 | 42 | void PntSetCoord(Point point, int i, double value) { 43 | LstSet(point, i, value); // so easy 44 | } 45 | 46 | Point PntAdd(Point a, Point b) { 47 | int n = PntGetDim(a); 48 | Point point = LstCreate(n); 49 | 50 | for(int i = 0; i < n; i++) 51 | LstSet(point, i, LstGet(a, i) + LstGet(b, i)); 52 | 53 | return point; 54 | } 55 | 56 | // scales a point by a scalar factor 57 | Point PntScale(Point point, double factor) { 58 | int n = PntGetDim(point); 59 | Point newpoint = LstCreate(n); 60 | 61 | for(int i = 0; i < n; i++) 62 | LstSet(newpoint, i, factor * LstGet(point, i)); 63 | 64 | return newpoint; 65 | } 66 | 67 | // returns the euclidean norm of a point 68 | // https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm 69 | // 70 | double PntNorm(Point point) { 71 | int n = PntGetDim(point); 72 | double sum = 0; 73 | for(int i = 0; i < n; i++) { 74 | double x = LstGet(point, i); 75 | sum += x*x; 76 | } 77 | return sqrt(sum); 78 | } 79 | 80 | // returns the (Euclidean) distance between two points 81 | double PntDistance(Point a, Point b) { 82 | // the distance between a and b is the norm of (a-b) 83 | return PntNorm(PntAdd(a, PntScale(b, -1))); 84 | } 85 | 86 | void PntPrint(Point point) { 87 | int n = PntGetDim(point); 88 | printf("("); 89 | for(int i = 0; i < n; i++) { 90 | if(i > 0) 91 | printf(", "); 92 | printf("%f", LstGet(point, i)); 93 | } 94 | printf(")"); 95 | } 96 | 97 | // auxiliary function that compares 2 doubles. 98 | // CAREFULL: never use == for doubles, but check whether abs(a-b) is small 99 | // 100 | static int CompareDoubles(double a, double b) { 101 | return abs(a - b) > 1e-6; 102 | } 103 | 104 | int PntCompare(Point a, Point b) { 105 | // We know how to compare lists! Just pass a proper compare function, in our case one that compares doubles. 106 | return LstCompare(a, b, CompareDoubles); 107 | 108 | // NOTE: this also works (just a bit slower) 109 | // return CompareDoubles(PntDistance(a, b), 0); 110 | } 111 | -------------------------------------------------------------------------------- /project2/reusable_modules/modules/point/point.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | 4 | // A module for working with n-dimentional points 5 | // 6 | // Implemented as lists (use make LST_IMPL=[linked,sequential] to choose the implementation 7 | // 8 | #include "list.h" 9 | 10 | 11 | // Types 12 | // 13 | typedef LstList Point; // out Points are really just lists (but the user shouldn't care about this) 14 | 15 | 16 | // Functions 17 | // 18 | // 19 | // creates an n-dimentional 1-point (i.e. having n coordinates, all 1) 20 | // 21 | Point PntOne(int n); 22 | 23 | // Easy creation of a 2d-point 24 | // 25 | Point Pnt2D(double x, double y); 26 | 27 | // Easy creation of a 3d-point 28 | // 29 | Point Pnt3D(double x, double y, double z); 30 | 31 | // returns the dimention of a point 32 | int PntGetDim(Point point); 33 | 34 | // returns the i-th coordinate of a point 35 | double PntGetCoord(Point point, int i); 36 | 37 | // sets the i-th coordinate of a point 38 | void PntSetCoord(Point point, int i, double value); 39 | 40 | // adds two n-dimentional points 41 | Point PntAdd(Point a, Point b); 42 | 43 | // scales a point by a scalar factor 44 | Point PntScale(Point point, double factor); 45 | 46 | // returns the euclidean norm of a point (https://en.wikipedia.org/wiki/Norm_(mathematics)#Euclidean_norm) 47 | double PntNorm(Point point); 48 | 49 | // returns the (Euclidean) distance between two points 50 | double PntDistance(Point a, Point b); 51 | 52 | // prints a point the (Euclidean) distance between two points 53 | void PntPrint(Point point); 54 | 55 | // return 0 if a == b, non-0 otherwize 56 | int PntCompare(Point a, Point b); -------------------------------------------------------------------------------- /project2/reusable_modules/modules/stack/list_item.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // This file is part of the stack module. 4 | // 5 | // We use lists, so we need to set the LstItem properly. 6 | // The list will store the elements of the stack, which 7 | // have type StItem, so... 8 | 9 | #include "stack_item.h" // we need to know what StItem is, it is defined here! 10 | 11 | typedef StItem LstItem; // store stack items (type StItem) in the list -------------------------------------------------------------------------------- /project2/reusable_modules/modules/stack/make.inc: -------------------------------------------------------------------------------- 1 | # This file is part of the stack module. 2 | # 3 | # Anyone who wants to use the stack module should include this file in their 4 | # Makefile, so that compilation is configured properly 5 | # 6 | 7 | # Set compiler flags. -I... tells the compiler to look in our directory for 8 | # include files, so that #include "stack.h" works. 9 | # 10 | CFLAGS += -I$(MODULES)/stack 11 | 12 | # We need to compile stack.o 13 | # 14 | OBJS += $(MODULES)/stack/stack.o 15 | 16 | # We use the list module, include its make.inc so that it can configure itself. 17 | # 18 | include $(MODULES)/list/make.inc 19 | -------------------------------------------------------------------------------- /project2/reusable_modules/modules/stack/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "stack.h" 5 | 6 | 7 | // The real struct. Only this file needs to know it! 8 | // 9 | struct st_stack { 10 | int count; // we need to keep how many items we current have in the stack 11 | LstList list; // and the list containing the items 12 | }; 13 | 14 | 15 | StStack StCreate(int maxlen) { 16 | StStack stack = malloc(sizeof(*stack)); 17 | stack->count = 0; 18 | stack->list = LstCreate(maxlen); 19 | return stack; 20 | } 21 | 22 | int StEmpty(StStack stack) { 23 | return stack->count == 0; 24 | } 25 | 26 | void StInsert(StStack stack, StItem item) { 27 | LstSet(stack->list, stack->count, item); 28 | stack->count++; 29 | } 30 | 31 | StItem StRemove(StStack stack) { 32 | assert(!StEmpty(stack)); // terminate if stack is empty 33 | 34 | stack->count--; 35 | return LstGet(stack->list, stack->count); 36 | } 37 | -------------------------------------------------------------------------------- /project2/reusable_modules/modules/stack/stack.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // A stack, implemented using the list module 4 | // 5 | #include "list.h" // we need lists 6 | 7 | // The stack contains items of type StItem. It's the _user's_ job to define StItem (not ours). 8 | // He should make sure that a "stack_item.h" file is accessible by the compiler and defines StItem 9 | // 10 | #include "stack_item.h" // StItem should be defined here 11 | 12 | // Types 13 | // 14 | // The following declares an "incomplete" struct. The real struct is defined in stack.c, 15 | // the outside world need not know what's there (information hiding). 16 | // StStack is also declared as a pointer to this struct. 17 | // 18 | typedef struct st_stack *StStack; 19 | 20 | 21 | // Functions 22 | // 23 | StStack StCreate(int maxlen); 24 | int StEmpty(StStack stack); 25 | void StInsert(StStack stack, StItem item); 26 | StItem StRemove(StStack stack); 27 | 28 | -------------------------------------------------------------------------------- /project3/generic_lists/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # just check that all demos compile 3 | all: 4 | cd demo_union && make 5 | cd demo_voidpointer && make 6 | cd demo_untyped && make 7 | cd demo_template && make 8 | cd demo_symboltable && make 9 | 10 | run: 11 | cd demo_union && make run 12 | cd demo_voidpointer && make run 13 | cd demo_untyped && make run 14 | cd demo_template && make run 15 | cd demo_symboltable && make run 16 | -------------------------------------------------------------------------------- /project3/generic_lists/README.mkd: -------------------------------------------------------------------------------- 1 | 2 | ### generic_lists 3 | 4 | Επίδειξη διαφορετικών λύσεων για χρήση λιστών **διαφορετικών τύπων** (λίστας από strings και λίστας από ακεραίους) 5 | στο **ίδιο πρόγραμμα**. 6 | 7 | #### Usage 8 | 9 | ``` 10 | cd demo_union 11 | make run 12 | 13 | cd demo_voidpointer 14 | make run 15 | 16 | cd demo_untyped 17 | make run 18 | 19 | cd demo_template 20 | make run 21 | ``` 22 | 23 | #### Περιγραφή 24 | 25 | Στη C μπορούμε να φτιάξουμε μια λίστα από items αυθαίρετου τύπου βάζοντας το item να έχει 26 | τύπο LLItem τον οποίο ορίζει ο χρήστης με typedef. Μια τέτοια λίστα λέγεται **"typed"**, γιατί 27 | ο compiler γνωρίζει τον τύπο του item και ελέγχει ότι τον περνάμε σωστά (μας βοηθάει δηλαδή 28 | να εντοπίζουμε λάθη). 29 | 30 | Τι γίνεται όμως αν **στο ίδιο πρόγραμμα** θέλουμε μια λίστα από strings, και **ταυτόχρονα** μια λίστα 31 | από ints; Προφανώς δεν μπορεί το LLItem να είναι ταυτόχρονα char* και int! **Δε θέλουμε όμως 32 | να ξαναγράφουμε τον ίδιο κώδικα** για κάθε λίστα! 33 | 34 | Δυστυχώς η C δεν παρέχει μια 100% ικανοποιητική λύση, πάρα ταύτα υπάρχουν αρκετές επιλογές για να 35 | επιτευχτεί αυτός ο στόχος, ορισμένες απο τις οποίες επιδευκνύονται σε αυτό το project. 36 | 37 | #### Λύση 1 : LLItem = union 38 | 39 | Ενα union είναι σαν ένα struct το οποίο όμως αποθηκεύει **ένα** από τα πεδία τη φορά (όχι όλα μαζί). 40 | Οπότε μια απλή λύση είναι να ορίσουμε 41 | ``` 42 | typedef union { 43 | char* string; // store strings here 44 | int integer; // store ints here 45 | } LLItem; 46 | ``` 47 | Αν θέλουμε λίστα από ακεραίους χρησιμοποιούμε απλά το ```.integer``` πεδίο του union, διαφορετικά 48 | το ```.string``` πεδίο. (Πρέπει βέβαια εμείς να θυμόμαστε τι από τα δύο χρησιμοποιούμε, η C 49 | δεν μας το λέει αυτό.) 50 | 51 | Η λύση αυτή επιδεικνύεται στο [demo_union](demo_union) 52 | (χρησιμοποιώντας την υλοποίηση λίστας του [list_typed](modules/list_typed) module). 53 | 54 | - Θετικά 55 | - Απλή λύση 56 | - Ακόμα και με τους πολλαπλούς τύπους η λίστα παραμένει "semi-typed" : o compiler ελέγχει 57 | ότι το ```item.integer``` είναι πάντα ακέραιος (αλλά εμείς πρέπει να επιλέξουμε σωστά το πεδίο). 58 | - Αρνητικά 59 | - Το μέγεθος του union είναι ίσο με το μέγεθος του **μεγαλύτερου** πεδίου του. Οπότε αν κάποια 60 | από τις λίστες που θέλουμε έχει μεγάλο item, τότε **όλες** θα έχουν μεγάλο item, σπαταλώντας χώρο. 61 | - Ολοι οι χρήστες της λίστας πρέπει να "συντονιστούν" για να ορίσουν το εννιαίο LLItem. 62 | 63 | 64 | #### Λύση 2 : LLItem = void* 65 | 66 | Αντί να αποθηκεύουμε τα δεδομένα αποθηκεύουμε **pointers σε αυτά**! Οποιοσδήποτε pointer 67 | μπορεί να γίνει cast σε void* οπότε θέτωντας LLItem = void* μπορούμε να αποθηκεύσουμε 68 | διαφορετικών τύπων δεδομένα. 69 | 70 | Η λύση αυτή επιδεικνύεται στο [demo_voidpointer](demo_voidpointer) 71 | (χρησιμοποιώντας την υλοποίηση λίστας του [list_typed](modules/list_typed) module). 72 | 73 | - Θετικά 74 | - Σχετικά απλή λύση 75 | - Αρνητικά 76 | - Η χρήση της λίστας με αυτόν τον τρόπο είναι ουσιαστικά untyped 77 | (αλλά διατηρούμε τη δυνατότητα να χρησιμοποιήσουμε τη λίστα με typed τρόπο σε άλλα προγράμματα). 78 | - Μέρος του memory management περνάει στο χρήστη. ΕΦόσον αποθηκεύουμε ένα pointer στον ακέραιο 79 | 42, και όχι το ίδιο το 42, πρέπει εμείς να κάνουμε malloc, να βάλουμε το 42 στη μνήμη, να 80 | αποθηκεύσουμε τον pointer στη λίστα, και να κάνουμε free μετά. 81 | 82 | 83 | #### Λύση 3 : untyped list 84 | 85 | Χρησιμοποιούμε μια πλήρως untyped λίστα. Δεν υπάρχει δηλαδή LLItem καθόλου. 86 | Αντί να γνωρίζει τον τύπο του item, η λίστα γνωρίζει μόνο το _μέγεθος_ ```item_size``` του τύπου (όρισμα στην Create). Σε κάθε insert η λίστα παίρνει έναν pointer (void*) στα δεδομένα, 87 | και τα **αντιγράφει** στον κόμβο (**δεν αποθηκεύει pointers** δηλαδή, αλλά τα ίδια τα δεδομένα). 88 | 89 | Μια untyped υλοποίηση λίστας υπάρχει στο [list_untyped](modules/list_untyped) module, 90 | και επιδεικνύεται στο [demo_untyped](demo_untyped). 91 | 92 | - Θετικά 93 | - Ολο το memory management γίνεται από τη λίστα 94 | - Εφόσον είναι untyped, η λίστα μπορεί να δοθεί στο χρήστη σε **compiled** μορφή 95 | (αυτό δεν γίνεται σε typed lists γιατί κατά το compilation πρέπει να είναι γνωστό 96 | το LLItem το οποίο όμως το δίνει ο χρήστης!) 97 | - Αρνητικά 98 | - fully untyped λύση (δεν υπάρχει καμία δυνατότητα για typed items) 99 | 100 | 101 | #### Λύση 4 : template list 102 | 103 | Τα templates της C++ είναι ένα feature που κάνει ακριβώς αυτό που θέλουμε : επιτρέπει 104 | τη δημιουργία δομών με ``παράμετρο'' τον τύπο. Δυστυχώς αυτό δεν είναι ακριβώς C, αλλά 105 | από την άλλη η C++ είναι (σχεδόν) υπερσύνολο της C. Οπότε μπορούμε να γράφουμε κανονικά C κώδικα 106 | και να χρησιμοποιήσουμε **μόνο τα templates** της C++, χωρίς κανένα άλλο από τα πιο προχωρημένα 107 | features της. Αυτή τη γλώσσα θα μπορούσαμε να την ονομάσουμε "template-C", η χρήση 108 | templates ελάχιστα αλλάζει τη μορφή του κώδικα όπως την ξέρουμε στη C. 109 | 110 | Με τη χρήση templates δεν υπάρχει πια `LLItem`, και η λίστα από `LLList` γίνεται `LLList`, όπου `T` 111 | ο τύπος του item. Και μπορούμε να χρησιμοποιούμε λίστες `LLList`, `LLList`, κλπ, στο ίδιο 112 | πρόγραμμα. 113 | 114 | Κατά τα άλλα ο κώδικας αλλάζει μόνο στη δήλωση των structs και των συναρτήσεων με "template" τρόπο, 115 | έχοντας δηλαδή πάντα μια παράμετρο `T`. Πχ 116 | ``` 117 | template // a template struct! T is a type parameter 118 | struct mystruct { 119 | T item; // item, of type T 120 | }; 121 | ``` 122 | Οι συναρτήσεις μπορούν επίσης να έχουν έναν τύπο ως παράμετρο: 123 | ``` 124 | template // a template function! T is a type parameter 125 | T foo(T a) { // takes an argument of type T, returns a value of type T 126 | return a + 1; 127 | } 128 | ``` 129 | και καλούνται ως 130 | ``` 131 | foo(15); // returns 16 132 | foo(5.3); // returns 6.3 133 | ``` 134 | Το `` στις κλήσεις `foo` μπορεί συχνά να παραλειφθεί αν ο compiler μπορεί να καταλάβει 135 | τον τύπο από τα ορίσματα της συνάρτησης! 136 | 137 | Κατά τα άλλα ο κώδικας αλλάζει ελάχιστα. Μια διαφορά είναι ότι **όλος ο κώδικας υπάρχει 138 | στο .h αρχείο** (δεν υπάρχει .c), και πρέπει βέβαια να κάνουμε compile με g++, όχι gcc. 139 | 140 | Μια template υλοποίηση λίστας υπάρχει στο [list_template](modules/list_template) module, 141 | και επιδεικνύεται στο [demo_template](demo_template). 142 | 143 | - Θετικά 144 | - Fully typed 145 | - Σχετικά απλός κώδικας, με λίγες αλλαγές σε σχέση με την non-template version 146 | - Αρνητικά 147 | - Δεν είναι pure C -------------------------------------------------------------------------------- /project3/generic_lists/demo_symboltable/Makefile: -------------------------------------------------------------------------------- 1 | # Where are our moduleS? 2 | MODULES = ../modules 3 | 4 | # Set compiler options here. 5 | # Set -I. so that include files in this directory are always found (even when compiling the modules in other dirs) 6 | # 7 | CFLAGS = -g -Wall -I. 8 | 9 | # set the name of the executable file to compile here 10 | PROGRAM = demo_symboltable 11 | 12 | # List object files needed to compile the program. 13 | OBJS = main.o 14 | 15 | # We use two modules, include their make.inc so that they can configure themselves 16 | include $(MODULES)/list_typed/make.inc 17 | include $(MODULES)/SymbolTable/make.inc 18 | 19 | 20 | # Quick and dirty: always clean before building! (by having "clean" as a dependency) 21 | $(PROGRAM): clean $(OBJS) 22 | $(CC) $(OBJS) -o $(PROGRAM) -lm 23 | 24 | clean: 25 | rm -f $(PROGRAM) $(OBJS) 26 | 27 | run: $(PROGRAM) 28 | ./$(PROGRAM) 29 | 30 | -------------------------------------------------------------------------------- /project3/generic_lists/demo_symboltable/STItem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "list_types.h" 3 | 4 | // ο τύπος των items του symbol table 5 | typedef union { 6 | int integer; 7 | char *string; 8 | LLList list; 9 | } STItem; -------------------------------------------------------------------------------- /project3/generic_lists/demo_symboltable/list_item.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // This file is part of demo_union 4 | // This demo uses typed lists, so we need to set the LLItem properly. 5 | 6 | #include "SymbolTable.h" 7 | 8 | typedef union { 9 | char *string; 10 | int integer; 11 | LLList list; 12 | STPair st_pair; 13 | } LLItem; 14 | -------------------------------------------------------------------------------- /project3/generic_lists/demo_symboltable/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "list.h" 6 | #include "SymbolTable.h" 7 | 8 | 9 | void visit_int(STTable table, STKey key, STItem item) { 10 | printf("%s => %d\n", key, item.integer); 11 | } 12 | 13 | void visit_str(STTable table, STKey key, STItem item) { 14 | printf("%s => %s\n", key, item.string); 15 | } 16 | 17 | void visit_list(STTable table, STKey key, STItem item) { 18 | printf("%s => list of %d elements\n", key, LLLength(item.list)); 19 | } 20 | 21 | int main() { 22 | // symbol table of ints 23 | STTable table = STCreate(); 24 | 25 | STInsert(table, "foo", (STItem){ .integer = 1 }); 26 | STInsert(table, "foo", (STItem){ .integer = 2 }); 27 | STInsert(table, "bar", (STItem){ .integer = 3 }); 28 | 29 | STVisit(table, visit_int); 30 | 31 | printf("size: %d\n", STSize(table)); 32 | STDestroy(table); 33 | 34 | // symbol table of strings 35 | STTable table2 = STCreate(); 36 | 37 | STInsert(table2, "foo", (STItem){ .string = "foo" }); 38 | STInsert(table2, "bar", (STItem){ .string = "bar" }); 39 | 40 | STVisit(table2, visit_str); 41 | printf("size: %d\n", STSize(table2)); 42 | STDestroy(table2); 43 | 44 | // symbol table of lists 45 | STTable table3 = STCreate(); 46 | 47 | LLList list = LLCreate(); 48 | LLInsertAfter(list, LL_NIL, (LLItem){ .integer = 1 }); 49 | 50 | STInsert(table3, "foo", (STItem){ .list = list }); 51 | STInsert(table3, "bar", (STItem){ .list = list }); 52 | 53 | STVisit(table3, visit_list); 54 | printf("size: %d\n", STSize(table3)); 55 | STDestroy(table3); 56 | 57 | } -------------------------------------------------------------------------------- /project3/generic_lists/demo_template/Makefile: -------------------------------------------------------------------------------- 1 | # Where are our moduleS? 2 | MODULES = ../modules 3 | 4 | # compile with g++ (although we use .c files) 5 | CC=g++ 6 | 7 | # Set compiler options here. 8 | # 9 | CFLAGS = -g -Wall -std=c++11 10 | 11 | # set the name of the executable file to compile here 12 | PROGRAM = demo_template 13 | 14 | # List object files needed to compile the program. 15 | OBJS = main.o 16 | 17 | # We use the list module, include its make.inc so that it can configure itself 18 | include $(MODULES)/list_template/make.inc 19 | 20 | 21 | # Quick and dirty: always clean before building! (by having "clean" as a dependency) 22 | $(PROGRAM): clean $(OBJS) 23 | $(CC) $(OBJS) -o $(PROGRAM) 24 | 25 | clean: 26 | rm -f $(PROGRAM) $(OBJS) 27 | 28 | run: $(PROGRAM) 29 | ./$(PROGRAM) 30 | 31 | -------------------------------------------------------------------------------- /project3/generic_lists/demo_template/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "list.h" 6 | 7 | // Demo που δείχνει τη χρήστη λίστας από strings και ints στο ίδιο πρόγραμμα, 8 | // χρησιμοποιώντας μια template list. 9 | 10 | 11 | // Στη λίστα θα βάζουμε "constant strings", όπως πχ ένα string literal "A". Στη C++ αυτά έχουν τύπο const char* 12 | // 13 | typedef const char *CStr; // constant string 14 | 15 | // typedefs for easier to write/understand code 16 | typedef LLList StringList; 17 | typedef LLNode StringNode; 18 | 19 | typedef LLList IntList; 20 | typedef LLNode IntNode; 21 | 22 | 23 | 24 | // ------------ strings ----------------- 25 | 26 | int compare_strings(CStr a, CStr b) { 27 | return strcmp(a, b); 28 | } 29 | 30 | void visit_string(StringList list, StringNode node) { 31 | printf("%s\n", LLGetItem(list, node)); 32 | } 33 | 34 | StringList create_string_list() { 35 | CStr strings[] = { "A", "B", "C", "D", "E" }; 36 | 37 | StringList list = LLCreate(); // needed, cannot infer type 38 | StringNode node = LL_NIL; 39 | 40 | for(int i = 0; i < 5; i++) 41 | node = LLInsertAfter(list, node, strings[i]); 42 | 43 | return list; 44 | } 45 | 46 | void demo_string() { 47 | // list of strings 48 | StringList list = create_string_list(); 49 | 50 | printf("A exists?: %d\n", LLFind(list, "A", compare_strings) != LL_NIL); 51 | printf("Z exists?: %d\n", LLFind(list, "Z", compare_strings) != LL_NIL); 52 | 53 | LLRemove(list, LLNext(list, LLNext(list, LL_NIL))); // remove 2nd element 54 | LLVisit(list, visit_string); 55 | 56 | LLDestroy(list); 57 | } 58 | 59 | // ------------ ints ----------------- 60 | 61 | int compare_ints(int a, int b) { 62 | return a - b; 63 | } 64 | 65 | void visit_int(IntList list, IntNode node) { 66 | printf("%d\n", LLGetItem(list, node)); 67 | } 68 | 69 | IntList create_int_list() { 70 | IntList list = LLCreate(); // needed, cannot infer type! 71 | IntNode node = LL_NIL; 72 | 73 | for(int i = 0; i < 5; i++) 74 | node = LLInsertAfter(list, node, i); 75 | 76 | return list; 77 | } 78 | 79 | void demo_int() { 80 | // list of int 81 | IntList list = create_int_list(); 82 | 83 | printf("4 exists?: %d\n", LLFind(list, 4, compare_ints) != LL_NIL); 84 | printf("7 exists?: %d\n", LLFind(list, 7, compare_ints) != LL_NIL); 85 | 86 | LLRemove(list, LLNext(list, LLNext(list, LL_NIL))); // remove 2nd element 87 | LLVisit(list, visit_int); 88 | } 89 | 90 | 91 | int main() { 92 | demo_string(); 93 | demo_int(); 94 | } -------------------------------------------------------------------------------- /project3/generic_lists/demo_union/Makefile: -------------------------------------------------------------------------------- 1 | # Where are our moduleS? 2 | MODULES = ../modules 3 | 4 | # Set compiler options here. 5 | # Set -I. so that include files in this directory are always found (even when compiling the modules in other dirs) 6 | # 7 | CFLAGS = -g -Wall -I. 8 | 9 | # set the name of the executable file to compile here 10 | PROGRAM = demo_union 11 | 12 | # List object files needed to compile the program. 13 | OBJS = main.o 14 | 15 | # We use the list module, include its make.inc so that it can configure itself 16 | include $(MODULES)/list_typed/make.inc 17 | 18 | 19 | # Quick and dirty: always clean before building! (by having "clean" as a dependency) 20 | $(PROGRAM): clean $(OBJS) 21 | $(CC) $(OBJS) -o $(PROGRAM) -lm 22 | 23 | clean: 24 | rm -f $(PROGRAM) $(OBJS) 25 | 26 | run: $(PROGRAM) 27 | ./$(PROGRAM) 28 | 29 | -------------------------------------------------------------------------------- /project3/generic_lists/demo_union/list_item.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // This file is part of demo_union 4 | // This demo uses typed lists, so we need to set the LLItem properly. 5 | 6 | 7 | // Στο πρόγραμμά μας θέλουμε λίστες ακεραίων ή λίστες από strings. Οπότε μπορούμε το LLItem 8 | // να είναι ένα union που περιέχει είτε έναν ακέραιο είτε ένα string. 9 | // 10 | // ΠΡΟΣΟΧΗ: δε θέλουμε λίστες με strings ΚΑΙ ints μαζί. Ενα struct θα αποθήκευε ένα string 11 | // ΚΑΙ ένα int. Εμείς θέλουμε string Η int. 12 | 13 | typedef union { 14 | char* string; // store strings here 15 | int integer; // store ints here 16 | } LLItem; 17 | -------------------------------------------------------------------------------- /project3/generic_lists/demo_union/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "list.h" 5 | 6 | // Demo που δείχνει τη χρήση μια typed list με διαφορετικά types 7 | // στο ίδιο πρόγραμμα, θέτωντας LLItem = union από string/int 8 | 9 | 10 | 11 | // ------------ strings ----------------- 12 | 13 | int compare_strings(LLItem a, LLItem b) { // the params are unions! 14 | return strcmp(a.string, b.string); // use the string part 15 | } 16 | 17 | void visit_string(LLList list, LLNode node) { 18 | printf("%s\n", LLGetItem(list, node).string); // use the string part 19 | } 20 | 21 | LLList create_string_list() { 22 | char* strings[] = { "A", "B", "C", "D", "E" }; 23 | 24 | LLList list = LLCreate(); 25 | LLNode node; 26 | 27 | for(int i = 0; i < 5; i++) { 28 | LLItem item = { .string = strings[i] }; // initialize the union with a string 29 | node = LLInsertAfter(list, node, item); 30 | } 31 | 32 | return list; 33 | } 34 | 35 | void demo_string() { 36 | // list of strings 37 | LLList list = create_string_list(); 38 | 39 | LLItem item; // we need an LLItem (union) for LLFind 40 | 41 | item.string = "A"; 42 | printf("A exists?: %d\n", LLFind(list, item, compare_strings) != LL_NIL); 43 | item.string = "Z"; 44 | printf("Z exists?: %d\n", LLFind(list, item, compare_strings) != LL_NIL); 45 | 46 | LLRemove(list, LLNext(list, LLNext(list, LL_NIL))); // remove 2nd element 47 | LLVisit(list, visit_string); 48 | 49 | // Τα items είναι string literals, δεν τα έχουμε κάνει εμείς malloc. Οπότε πρέπει μόνο να κάνουμε free τη λίστα 50 | LLDestroy(list); 51 | } 52 | 53 | 54 | // ------------ ints ----------------- 55 | 56 | LLList create_int_list() { 57 | LLList list = LLCreate(); 58 | LLNode node = LL_NIL; 59 | 60 | for(int i = 0; i < 5; i++) { 61 | LLItem item = { .integer = i }; // initialize the union with an integer 62 | node = LLInsertAfter(list, node, item); 63 | } 64 | 65 | return list; 66 | } 67 | 68 | int compare_ints(LLItem a, LLItem b) { // params are LLItems (unions)! 69 | return a.integer - b.integer; // compare the integer parts 70 | } 71 | 72 | void visit_int(LLList list, LLNode node) { 73 | printf("%d\n", LLGetItem(list, node).integer); // get the integer part 74 | } 75 | 76 | void demo_int() { 77 | // list of int 78 | LLList list = create_int_list(); 79 | 80 | LLItem item; // we need an LLItem (union) for LLFind 81 | 82 | item.integer = 4; 83 | printf("4 exists?: %d\n", LLFind(list, item, compare_ints) != LL_NIL); 84 | item.integer = 7; 85 | printf("7 exists?: %d\n", LLFind(list, item, compare_ints) != LL_NIL); 86 | 87 | LLRemove(list, LLNext(list, LLNext(list, LL_NIL))); // remove 2nd element 88 | LLVisit(list, visit_int); 89 | 90 | LLDestroy(list); 91 | } 92 | 93 | 94 | int main() { 95 | demo_string(); 96 | demo_int(); 97 | } -------------------------------------------------------------------------------- /project3/generic_lists/demo_untyped/Makefile: -------------------------------------------------------------------------------- 1 | # Where are our moduleS? 2 | MODULES = ../modules 3 | 4 | # Set compiler options here. 5 | # 6 | CFLAGS = -g -Wall 7 | 8 | # set the name of the executable file to compile here 9 | PROGRAM = demo_untyped 10 | 11 | # List object files needed to compile the program. 12 | OBJS = main.o 13 | 14 | # We use the list module, include its make.inc so that it can configure itself 15 | include $(MODULES)/list_untyped/make.inc 16 | 17 | 18 | # Quick and dirty: always clean before building! (by having "clean" as a dependency) 19 | $(PROGRAM): clean $(OBJS) 20 | $(CC) $(OBJS) -o $(PROGRAM) -lm 21 | 22 | clean: 23 | rm -f $(PROGRAM) $(OBJS) 24 | 25 | run: $(PROGRAM) 26 | ./$(PROGRAM) 27 | 28 | -------------------------------------------------------------------------------- /project3/generic_lists/demo_untyped/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "list.h" 5 | 6 | // Demo που δείχνει τη χρήση μιας untyped list για αποθήκευση λίστας από strings 7 | // και ints στο ίδιο πρόγραμμα. 8 | 9 | 10 | 11 | // ------------ strings ----------------- 12 | 13 | int compare_strings(void *a, void *b) { // the params need to be void* ! 14 | // ΠΡΟΣΟΧΗ 15 | // Η λίστα αποθηκεύει char*, οπότε μας περνάει pointer σε char* (δηλαδή char**) 16 | char **ap = a; 17 | char **bp = b; 18 | return strcmp(*ap, *bp); 19 | } 20 | 21 | void visit_string(LLList list, LLNode node) { 22 | // ΠΡΟΣΟΧΗ 23 | // Η λίστα περιέχει char*. Η GetItem επιστρέφει _pointer_ σε char* δηλαδή char** 24 | char **sp = LLGetItem(list, node); 25 | printf("%s\n", *sp); 26 | } 27 | 28 | LLList create_string_list() { 29 | char* strings[] = { "A", "B", "C", "D", "E" }; 30 | 31 | LLList list = LLCreate(sizeof(char*)); // a list of char* 32 | LLNode node; 33 | 34 | // ΠΡΟΣΟΧΗ 35 | // Η λίστα περιέχει char* οπότε στην LLInsertAfter πρέπει να περάσουμε έναν _pointer_ σε char* 36 | // (δηλαδή char**) και όχι ένα char*. Δηλαδή &strings[i], όχι strings[i] 37 | for(int i = 0; i < 5; i++) 38 | node = LLInsertAfter(list, node, &strings[i]); 39 | 40 | return list; 41 | } 42 | 43 | void demo_string() { 44 | // list of strings 45 | LLList list = create_string_list(); 46 | 47 | char *s = "A"; 48 | printf("A exists?: %d\n", LLFind(list, &s, compare_strings) != LL_NIL); 49 | s = "Z"; 50 | printf("Z exists?: %d\n", LLFind(list, &s, compare_strings) != LL_NIL); 51 | 52 | LLRemove(list, LLNext(list, LLNext(list, LL_NIL))); // remove 2nd element 53 | LLVisit(list, visit_string); 54 | 55 | LLDestroy(list); 56 | } 57 | 58 | 59 | // ------------ ints ----------------- 60 | 61 | LLList create_int_list() { 62 | LLList list = LLCreate(sizeof(int)); // a list of int 63 | LLNode node = LL_NIL; 64 | 65 | for(int i = 0; i < 5; i++) { 66 | // Η λίστα αντιγράφει τον ακέραιο που της περνάμε, δεν κρατάει τον pointer! 67 | // Οπότε μπορούμε απλά να περάσουμε &i κι ας είναι τοπική μεταβλητή! 68 | node = LLInsertAfter(list, node, &i); 69 | } 70 | 71 | return list; 72 | } 73 | 74 | int compare_ints(void *a, void *b) { 75 | // Τα a,b είναι pointers σε int, οπότε φτιάχνουμε πραγματικούς int pointers και τους κάνουμε dereference 76 | int *ia = a; 77 | int *ib = b; 78 | return *ia - *ib; 79 | } 80 | 81 | void visit_int(LLList list, LLNode node) { 82 | // Η λίστα περιέχει ints, οπότε η LLGetItem επιστρέφει pointer σε int 83 | int *ip = LLGetItem(list, node); 84 | printf("%d\n", *ip); 85 | } 86 | 87 | void demo_int() { 88 | // list of int 89 | LLList list = create_int_list(); 90 | 91 | int i = 4; 92 | printf("4 exists?: %d\n", LLFind(list, &i, compare_ints) != LL_NIL); 93 | i = 7; 94 | printf("7 exists?: %d\n", LLFind(list, &i, compare_ints) != LL_NIL); 95 | 96 | LLRemove(list, LLNext(list, LLNext(list, LL_NIL))); // remove 2nd element 97 | LLVisit(list, visit_int); 98 | 99 | LLDestroy(list); // ολο το memory management γίνεται από το module, δεν κάναμε κάτι εμείς malloc! 100 | } 101 | 102 | 103 | int main() { 104 | demo_string(); 105 | demo_int(); 106 | } -------------------------------------------------------------------------------- /project3/generic_lists/demo_voidpointer/Makefile: -------------------------------------------------------------------------------- 1 | # Where are our moduleS? 2 | MODULES = ../modules 3 | 4 | # Set compiler options here. 5 | # Set -I. so that include files in this directory are always found (even when compiling the modules in other dirs) 6 | # 7 | CFLAGS = -g -Wall -I. 8 | 9 | # set the name of the executable file to compile here 10 | PROGRAM = demo_voidpointer 11 | 12 | # List object files needed to compile the program. 13 | OBJS = main.o 14 | 15 | # We use the list module, include its make.inc so that it can configure itself 16 | include $(MODULES)/list_typed/make.inc 17 | 18 | 19 | # Quick and dirty: always clean before building! (by having "clean" as a dependency) 20 | $(PROGRAM): clean $(OBJS) 21 | $(CC) $(OBJS) -o $(PROGRAM) -lm 22 | 23 | clean: 24 | rm -f $(PROGRAM) $(OBJS) 25 | 26 | run: $(PROGRAM) 27 | ./$(PROGRAM) 28 | 29 | -------------------------------------------------------------------------------- /project3/generic_lists/demo_voidpointer/list_item.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // This file is part of demo_voidpointer 4 | // 5 | // demo2 uses typed lists, so we need to set the LLItem properly. 6 | // 7 | // But we need to use _both_ string and int lists, so the solution is void* 8 | 9 | typedef void *LLItem; 10 | -------------------------------------------------------------------------------- /project3/generic_lists/demo_voidpointer/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "list.h" 6 | 7 | // Demo που δείχνει τη χρήση μια typed list με διαφορετικά types 8 | // στο ίδιο πρόγραμμα, θέτωντας LLItem = void* 9 | 10 | 11 | 12 | // ------------ strings ----------------- 13 | 14 | int compare_strings(void *a, void *b) { // the params need to be void* ! 15 | return strcmp(a, b); // auto cast void* -> char* 16 | } 17 | 18 | void visit_string(LLList list, LLNode node) { 19 | char *s = LLGetItem(list, node); // auto cast void* -> char* 20 | printf("%s\n", s); 21 | } 22 | 23 | LLList create_string_list() { 24 | // Ενα string s είναι pointer char*, η λίστα αποθηκεύει επίσης pointers, αλλά void*. 25 | // Οπότε μπορoυμε να αποθηκεύσουμε το _ίδιο_ το s στη λίστα, απλά κάνοντάς το cast 26 | // (το οποίο συχνά το κάνει αυτόματα η C). 27 | 28 | char* strings[] = { "A", "B", "C", "D", "E" }; 29 | 30 | LLList list = LLCreate(); 31 | LLNode node; 32 | 33 | for(int i = 0; i < 5; i++) 34 | node = LLInsertAfter(list, node, strings[i]); 35 | 36 | return list; 37 | } 38 | 39 | void demo_string() { 40 | // list of strings 41 | LLList list = create_string_list(); 42 | 43 | printf("A exists?: %d\n", LLFind(list, "A", compare_strings) != LL_NIL); 44 | printf("Z exists?: %d\n", LLFind(list, "Z", compare_strings) != LL_NIL); 45 | 46 | LLRemove(list, LLNext(list, LLNext(list, LL_NIL))); // remove 2nd element 47 | LLVisit(list, visit_string); 48 | 49 | // Τα items είναι string literals, δεν τα έχουμε κάνει εμείς malloc. Οπότε πρέπει μόνο να κάνουμε free τη λίστα 50 | LLDestroy(list); 51 | } 52 | 53 | 54 | // ------------ ints ----------------- 55 | 56 | LLList create_int_list() { 57 | // Θέλουμε να αποθηκεύυομε ints, αλλά η λίστα αποθηκεύει pointers (void*). 58 | // Οπότε δε θα αποθηκεύσουμε τον ίδιο τον ακέραιο, αλλά έναν pointer σε αυτόν! 59 | 60 | LLList list = LLCreate(); 61 | LLNode node = LL_NIL; 62 | 63 | for(int i = 0; i < 5; i++) { 64 | // ΠΡΟΣΟΧΗ 65 | // Η λίστα αποθηκεύει μόνο τον pointer, δεν αντιγράφει δεδομένα! 66 | // Το i είναι τοπική μεταβλητή, άρα χρειαζόμαστε malloc (δεν μπορούμε να βάλουμε item = &i) 67 | // 68 | int *item = malloc(sizeof(int)); 69 | *item = i; 70 | node = LLInsertAfter(list, node, item); // auto cast int* -> void* 71 | } 72 | 73 | return list; 74 | } 75 | 76 | int compare_ints(void *a, void *b) { 77 | // Τα a,b είναι στην πραγματικότητα pointers σε int, οπότε φτιάχνουμε πραγματικούς 78 | // int pointers και τους κάνουμε dereference 79 | int* ia = a; 80 | int* ib = b; 81 | return *ia - *ib; 82 | } 83 | 84 | void visit_int(LLList list, LLNode node) { 85 | // Το item είναι στην πραγματικότητα pointer σε int 86 | int* item = LLGetItem(list, node); // auto cast void* -> int* 87 | printf("%d\n", *item); 88 | } 89 | 90 | // Χρησιμοποιείται μαζί με τη visit για να κάνουμε free τα items της λίστας 91 | void free_item(LLList list, LLNode node) { 92 | free(LLGetItem(list, node)); 93 | } 94 | 95 | void demo_int() { 96 | // list of int 97 | LLList list = create_int_list(); 98 | 99 | int i = 4; 100 | printf("4 exists?: %d\n", LLFind(list, &i, compare_ints) != LL_NIL); 101 | i = 7; 102 | printf("7 exists?: %d\n", LLFind(list, &i, compare_ints) != LL_NIL); 103 | 104 | // ΠΡΟΣΟΧΗ: θέλουμε να αφαιρέσουμε το 2ο node, αλλά η λίστα αποθηκεύει απλά ένα int*, 105 | // είναι δική μας δουλειά να κάνουμε free το item! 106 | LLNode node = LLNext(list, LLNext(list, LL_NIL)); // 2nd node 107 | free(LLGetItem(list, node)); 108 | LLRemove(list, node); 109 | 110 | LLVisit(list, visit_int); 111 | 112 | // ΠΡΟΣΟΧΗ 113 | // Τα items είναι pointers που έχουμε εμείς κάνει malloc. Εμείς πρέπει και να τα κάνουμε free 114 | LLVisit(list, free_item); 115 | LLDestroy(list); 116 | } 117 | 118 | 119 | int main() { 120 | demo_string(); 121 | demo_int(); 122 | } -------------------------------------------------------------------------------- /project3/generic_lists/modules/SymbolTable/SymbolTable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "SymbolTable.h" 6 | #include "list.h" // στο SymbolTable.h γίνεται include μόνο το list_types.h, οπότε χρειζόμαστε και το list.h 7 | 8 | 9 | 10 | STTable STCreate() { 11 | return LLCreate(); 12 | } 13 | 14 | int STSize(STTable table) { 15 | return LLLength(table); 16 | } 17 | 18 | static int compare_llitems(LLItem a, LLItem b) { 19 | return strcmp(a.st_pair.key, b.st_pair.key); 20 | } 21 | 22 | int STGet(STTable table, STKey key, STItem *pitem) { 23 | STPair pair = { .key = key }; 24 | LLNode node = LLFind(table, (LLItem){ .st_pair = pair }, compare_llitems); 25 | if(node == LL_NIL) 26 | return 0; 27 | 28 | *pitem = LLGetItem(table, node).st_pair.item; 29 | return 1; 30 | } 31 | 32 | STItem STGetEx(STTable table, STKey key) { // return existing, **FAILS** if doesn't exists 33 | STItem item; 34 | assert(STGet(table, key, &item)); 35 | return item; 36 | } 37 | 38 | void STInsert(STTable table, STKey key, STItem item) { 39 | STRemove(table, key); 40 | 41 | STPair pair = { .key = strdup(key), .item = item }; 42 | LLInsertAfter(table, LL_NIL, (LLItem){ .st_pair = pair }); 43 | } 44 | 45 | void STRemove(STTable table, STKey key) { 46 | STPair pair = { .key = key }; 47 | LLNode node = LLFind(table, (LLItem){ .st_pair = pair }, compare_llitems); 48 | if(node != LL_NIL) 49 | LLRemove(table, node); 50 | } 51 | 52 | void STVisit(STTable table, STVisitFunc visit) { 53 | LLNode node = LL_NIL; 54 | while((node = LLNext(table, node)) != LL_NIL) { 55 | STPair pair = LLGetItem(table, node).st_pair; 56 | visit(table, pair.key, pair.item); 57 | } 58 | } 59 | 60 | // used by STDestroy 61 | static void destroy_keys(LLList list, LLNode node) { 62 | free(LLGetItem(list, node).st_pair.key); 63 | } 64 | 65 | void STDestroy(STTable table) { 66 | LLVisit(table, destroy_keys); // free keys 67 | LLDestroy(table); 68 | } -------------------------------------------------------------------------------- /project3/generic_lists/modules/SymbolTable/SymbolTable.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // A simple symbol table, implemented by a linked list 4 | // VERY inefficient 5 | 6 | #include "list_types.h" // χρειαζόμαστε μόνο το LLList, οπότε το list_types.h αρκεί! (για να αποφύγουμε κυκλικά includes) 7 | #include "STItem.h" // the user declares STItem here 8 | 9 | typedef char *STKey; 10 | typedef LLList STTable; 11 | 12 | typedef struct { 13 | STKey key; 14 | STItem item; 15 | } STPair; // key-item pair, stored in the list 16 | 17 | typedef void (*STVisitFunc )(STTable, STKey, STItem); // STVisitFunc: type of functions that visit 18 | 19 | STTable STCreate(); 20 | int STSize(STTable table); 21 | int STGet(STTable table, STKey key, STItem *pitem); 22 | STItem STGetEx(STTable table, STKey key); // return existing, **FAILS** if doesn't exists 23 | void STInsert(STTable table, STKey key, STItem item); 24 | void STRemove(STTable table, STKey key); 25 | void STVisit(STTable table, STVisitFunc visit); 26 | void STDestroy(STTable table); 27 | -------------------------------------------------------------------------------- /project3/generic_lists/modules/SymbolTable/make.inc: -------------------------------------------------------------------------------- 1 | ifndef ST_MAKE_INC # include guard for make.inc 2 | ST_MAKE_INC=1 3 | 4 | # This file is part of the list module. 5 | # 6 | # Anyone who wants to use the list module should include this file in their 7 | # Makefile, so that compilation is configured properly 8 | # 9 | 10 | # Set compiler flags. -I... tells the compiler to look in our directory for 11 | # include files, so that #include works. 12 | 13 | CFLAGS += -I$(MODULES)/SymbolTable 14 | 15 | OBJS += $(MODULES)/SymbolTable/SymbolTable.o 16 | 17 | 18 | endif #include guard 19 | -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_template/list.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // A simple linked list 4 | 5 | #define LL_NIL NULL // A "Nil" node is just NULL 6 | 7 | // Types (parametrized by T) 8 | 9 | template // a template struct! ll_node is a struct cointaining an item of type T 10 | struct ll_node { 11 | T item; // item, of type T 12 | struct ll_node *next; 13 | }; 14 | 15 | // "using" is just like typedef, but it can create template types! 16 | // 17 | template using LLNode = struct ll_node*; // LLNode is a pointer to "struct lst_node" 18 | template using LLList = LLNode; // LLList is just an LLNode (we use a dummy node to represent the whole list) 19 | 20 | template using LLCompareFunc = int (*)(T, T); // LLCompareFunc: type of functions that compare two T items 21 | template using LLVisitFunc = void (*)(LLList, LLNode);// LLVisitFunc: type of functions that visit a node 22 | 23 | 24 | // Function declarations (technically not really needed, but nice to have them for reference) 25 | 26 | // creates a new list 27 | 28 | template 29 | LLList LLCreate(); 30 | 31 | // destroys a list 32 | 33 | template 34 | void LLDestroy(LLList list); 35 | 36 | // returns the length of a list 37 | 38 | template 39 | int LLLength(LLList list); 40 | 41 | // returns the node after 'node'. Use node = LL_NIL to get the first. 42 | 43 | template 44 | LLNode LLNext(LLList list, LLNode node); 45 | 46 | // Returns the item of a non-Nil node 47 | 48 | template 49 | T LLGetItem(LLList list, LLNode node); 50 | 51 | // Inserts node after given one and returns it. Use node = LL_NIL to insert as first. 52 | 53 | template 54 | LLNode LLInsertAfter(LLList list, LLNode node, T item); 55 | 56 | // Removes a node 57 | 58 | template 59 | void LLRemove(LLList list, LLNode node); 60 | 61 | // Returns a node that matches the given item (or Nil if not found) 62 | 63 | template 64 | LLNode LLFind(LLList list, T item, LLCompareFunc compare); 65 | 66 | // Calls visit(list, node) on every node 67 | 68 | template 69 | void LLVisit(LLList list, LLVisitFunc visit); 70 | 71 | 72 | 73 | 74 | // For template functions, the implementation is also included in the .h file (there are no .c files!). 75 | // But we put it in a separate .h file for better organization, and include it here. 76 | // 77 | #include "list_impl.h" -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_template/list_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | #include 4 | #include 5 | 6 | // list implementation 7 | 8 | 9 | // auxiliary function to create a new node with a given next 10 | // 11 | template 12 | LLNode NewNode(LLNode next) { 13 | LLNode node = (LLNode)malloc(sizeof(*node)); 14 | node->next = next; 15 | return node; 16 | } 17 | 18 | 19 | template 20 | LLList LLCreate() { 21 | return NewNode(NULL); // empty list represented by a dummy node 22 | } 23 | 24 | template 25 | void LLDestroy(LLList list) { 26 | LLNode node = list; 27 | while(node != NULL) { 28 | LLNode next = node->next; // get this before free()! 29 | free(node); 30 | node = next; 31 | } 32 | } 33 | 34 | template 35 | int LLLength(LLList list) { 36 | // start from the first _real_ node, count them 37 | int res = 0; 38 | for(LLNode node = list->next; node != NULL; node = node->next) 39 | res++; 40 | return res; 41 | } 42 | 43 | template 44 | LLNode LLNext(LLList list, LLNode node) { 45 | return node == NULL ? list->next : node->next; 46 | } 47 | 48 | template 49 | T LLGetItem(LLList list, LLNode node) { 50 | assert(node != NULL); 51 | return node->item; 52 | } 53 | 54 | template 55 | LLNode LLInsertAfter(LLList list, LLNode node, T item) { 56 | if(node == NULL) // if node is null then 57 | node = list; // insert after the dummy! ( 58 | 59 | node->next = NewNode(node->next); 60 | node->next->item = item; 61 | return node->next; 62 | } 63 | 64 | template 65 | void LLRemove(LLList list, LLNode node) { 66 | // find the previous one (TODO: speedup using doubly linked list) 67 | for(LLNode prev = list; prev->next != NULL; prev = prev->next) 68 | if(prev->next == node) { 69 | prev->next = node->next; 70 | free(node); 71 | break; 72 | } 73 | } 74 | 75 | template 76 | LLNode LLFind(LLList list, T item, LLCompareFunc compare) { 77 | // iterate over list 78 | for(LLNode node = list->next; node != NULL; node = node->next) 79 | if(compare(item, node->item) == 0) 80 | return node; // found it 81 | 82 | return NULL; // it's not here 83 | } 84 | 85 | template 86 | void LLVisit(LLList list, LLVisitFunc visit) { 87 | // iterate over list 88 | for(LLNode node = list->next; node != NULL; node = node->next) 89 | visit(list, node); 90 | } -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_template/make.inc: -------------------------------------------------------------------------------- 1 | ifndef LL_MAKE_INC # include guard for make.inc 2 | LL_MAKE_INC=1 3 | 4 | # This file is part of the list module. 5 | # 6 | # Anyone who wants to use the list module should include this file in their 7 | # Makefile, so that compilation is configured properly 8 | # 9 | 10 | # Set compiler flags. -I... tells the compiler to look in our directory for 11 | # include files, so that #include "list.h" works. 12 | # 13 | CFLAGS += -I$(MODULES)/list_template 14 | 15 | 16 | endif #include guard -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_typed/list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "list.h" 5 | 6 | // information hiding: το struct ορίζεται εδώ, ο χρήστης δεν βλέπει τα περιεχόμενά του 7 | struct ll_node { 8 | LLItem item; // item, of type LLItem 9 | struct ll_node *next; 10 | }; 11 | 12 | 13 | // auxiliary function to create a new node with a given next 14 | // 15 | LLNode NewNode(LLNode next) { 16 | LLNode node = (LLNode)malloc(sizeof(*node)); 17 | node->next = next; 18 | return node; 19 | } 20 | 21 | 22 | LLList LLCreate() { 23 | return NewNode(NULL); // empty list represented by a dummy node 24 | } 25 | 26 | void LLDestroy(LLList list) { 27 | LLNode node = list; 28 | while(node != NULL) { 29 | LLNode next = node->next; // get this before free()! 30 | free(node); 31 | node = next; 32 | } 33 | } 34 | 35 | int LLLength(LLList list) { 36 | // start from the first _real_ node, count them 37 | int res = 0; 38 | for(LLNode node = list->next; node != NULL; node = node->next) 39 | res++; 40 | return res; 41 | } 42 | 43 | LLNode LLNext(LLList list, LLNode node) { 44 | return node == NULL ? list->next : node->next; 45 | } 46 | 47 | LLItem LLGetItem(LLList list, LLNode node) { 48 | assert(node != NULL); 49 | return node->item; 50 | } 51 | 52 | void LLSetItem(LLList list, LLNode node, LLItem item) { 53 | assert(node != NULL); 54 | node->item = item; 55 | } 56 | 57 | LLNode LLInsertAfter(LLList list, LLNode node, LLItem item) { 58 | if(node == NULL) // if node is null then 59 | node = list; // insert after the dummy! ( 60 | 61 | node->next = NewNode(node->next); 62 | node->next->item = item; 63 | return node->next; 64 | } 65 | 66 | void LLRemove(LLList list, LLNode node) { 67 | // find the previous one (TODO: speedup using doubly linked list) 68 | for(LLNode prev = list; prev->next != NULL; prev = prev->next) 69 | if(prev->next == node) { 70 | prev->next = node->next; 71 | free(node); 72 | break; 73 | } 74 | } 75 | 76 | LLNode LLFind(LLList list, LLItem item, LLCompareFunc compare) { 77 | // iterate over list 78 | for(LLNode node = list->next; node != NULL; node = node->next) 79 | if(compare(item, node->item) == 0) 80 | return node; // found it 81 | 82 | return NULL; // it's not here 83 | } 84 | 85 | void LLVisit(LLList list, LLVisitFunc visit) { 86 | // iterate over list 87 | for(LLNode node = list->next; node != NULL; node = node->next) 88 | visit(list, node); 89 | } -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_typed/list.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // A simple linked list 4 | 5 | #define LL_NIL NULL // A "Nil" node is just NULL 6 | 7 | #include "list_types.h" // include the basic types 8 | 9 | // The list is **typed**: it contains items of type LLItem. 10 | // It's the _user's_ job to define LLItem (not ours). 11 | // He should make sure that a "list_item.h" file is accessible by the compiler and defines LLItem 12 | // 13 | #include "list_item.h" 14 | 15 | typedef int (*LLCompareFunc )(LLItem, LLItem); // LLCompareFunc: type of functions that compare two LLItem items 16 | typedef void (*LLVisitFunc )(LLList, LLNode); // LLVisitFunc: type of functions that visit a node 17 | 18 | 19 | // Function declarations 20 | 21 | // creates a new list 22 | 23 | LLList LLCreate(); 24 | 25 | // destroys a list 26 | 27 | void LLDestroy(LLList list); 28 | 29 | // returns the length of a list 30 | 31 | int LLLength(LLList list); 32 | 33 | // returns the node after 'node'. Use node = LL_NIL to get the first. 34 | 35 | LLNode LLNext(LLList list, LLNode node); 36 | 37 | // Returns the item of a non-Nil node 38 | 39 | LLItem LLGetItem(LLList list, LLNode node); 40 | 41 | // Changes the item of a non-Nil node 42 | 43 | void LLSetItem(LLList list, LLNode node, LLItem Item); 44 | 45 | // Inserts node after given one and returns it. Use node = LL_NIL to insert as first. 46 | 47 | LLNode LLInsertAfter(LLList list, LLNode node, LLItem item); 48 | 49 | // Removes a node 50 | 51 | void LLRemove(LLList list, LLNode node); 52 | 53 | // Returns a node that matches the given item (or Nil if not found) 54 | 55 | LLNode LLFind(LLList list, LLItem item, LLCompareFunc compare); 56 | 57 | // Calls visit(list, node) on every node 58 | 59 | void LLVisit(LLList list, LLVisitFunc visit); 60 | -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_typed/list_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Στο αρχείο αυτό (list_types.h) βάζουμε τα βασικά types για λίστες: LLList && LLNode 4 | 5 | // Το πλεονέκτημα είναι ότι list_types.h δεν έχει _κανένα_ .h dependency, οπότε μπορούμε να κάνουμε 6 | // #include "listy_types.h" οπουδήποτε χωρίς να προκαλέσουμε κυκλικό include! 7 | 8 | // information hiding: ο χρήστης δεν χρειάζεται να γνωρίζει τί υπαρχει μέσα στο struct. 9 | // Πέρα από το information hiding, η χρήση "incomplete" structs μας επιτρέπει να ορίσουμε 10 | // το LLNode χωρίς να ξέρουμε το LLItem, αποφεύγοντας τα κυκλικά includes 11 | 12 | typedef struct ll_node *LLNode; // LLNode is a pointer to "struct lst_node" 13 | typedef LLNode LLList; // LLList is just an LLNode (we use a dummy node to represent the whole list) -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_typed/make.inc: -------------------------------------------------------------------------------- 1 | ifndef LL_MAKE_INC # include guard for make.inc 2 | LL_MAKE_INC=1 3 | 4 | # This file is part of the list module. 5 | # 6 | # Anyone who wants to use the list module should include this file in their 7 | # Makefile, so that compilation is configured properly 8 | # 9 | 10 | # Set compiler flags. -I... tells the compiler to look in our directory for 11 | # include files, so that #include "list.h" works. 12 | # 13 | CFLAGS += -I$(MODULES)/list_typed 14 | 15 | OBJS += $(MODULES)/list_typed/list.o 16 | 17 | 18 | endif #include guard -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_untyped/list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "list.h" 6 | 7 | // list implementation 8 | 9 | 10 | // auxiliary function to create a new node with a given next 11 | // 12 | LLNode NewNode(LLNode next) { 13 | LLNode node = (LLNode)malloc(sizeof(*node)); 14 | node->next = next; 15 | return node; 16 | } 17 | 18 | 19 | LLList LLCreate(int item_size) { 20 | LLList list = { 21 | .dummy = NewNode(NULL), 22 | .item_size = item_size 23 | }; 24 | return list; 25 | } 26 | 27 | void LLDestroy(LLList list) { 28 | LLNode node = list.dummy; 29 | while(node != NULL) { 30 | LLNode next = node->next; // get this before free()! 31 | free(node->item); // don't forget to free the item, not just the node! 32 | free(node); 33 | node = next; 34 | } 35 | } 36 | 37 | int LLLength(LLList list) { 38 | // start from the first _real_ node, count them 39 | int res = 0; 40 | for(LLNode node = list.dummy->next; node != NULL; node = node->next) 41 | res++; 42 | return res; 43 | } 44 | 45 | LLNode LLNext(LLList list, LLNode node) { 46 | return node == NULL ? list.dummy->next : node->next; 47 | } 48 | 49 | void *LLGetItem(LLList list, LLNode node) { 50 | assert(node != NULL); 51 | return node->item; 52 | } 53 | 54 | LLNode LLInsertAfter(LLList list, LLNode node, void *item) { 55 | if(node == NULL) // if node is null then 56 | node = list.dummy; // insert after the dummy! ( 57 | 58 | node->next = NewNode(node->next); 59 | node->next->item = malloc(list.item_size); 60 | memcpy(node->next->item, item, list.item_size); 61 | return node->next; 62 | } 63 | 64 | void LLRemove(LLList list, LLNode node) { 65 | // find the previous one (TODO: speedup using doubly linked list) 66 | for(LLNode prev = list.dummy; prev->next != NULL; prev = prev->next) 67 | if(prev->next == node) { 68 | prev->next = node->next; 69 | free(node); 70 | break; 71 | } 72 | } 73 | 74 | LLNode LLFind(LLList list, void *item, LLCompareFunc compare) { 75 | // iterate over list 76 | for(LLNode node = list.dummy->next; node != NULL; node = node->next) 77 | if(compare(item, node->item) == 0) 78 | return node; // found it 79 | 80 | return NULL; // it's not here 81 | } 82 | 83 | void LLVisit(LLList list, LLVisitFunc visit) { 84 | // iterate over list 85 | for(LLNode node = list.dummy->next; node != NULL; node = node->next) 86 | visit(list, node); 87 | } -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_untyped/list.h: -------------------------------------------------------------------------------- 1 | #pragma once // modern include guard 2 | 3 | // A simple untyped linked list 4 | // 5 | // Τα items της λίστας είναι _untyped_, δεν γνωρίζουμε τον τύπο τους (δεν υπάρχει δηλαδή LLItem). 6 | // Αντί αυτού, ξέρουμε μόνο το _μέγεθος_ item_size του τύπου (όρισμα στην Create). Η Insert παίρνει ένα 7 | // pointer στο item (void* αφού δεν ξέρουμε τον τύπο) και κάνει copy item_size bytes από εκεί. 8 | // Η GetItem επιστρέφει pointer στο item (όχι το ίδιο το item) 9 | 10 | 11 | #define LL_NIL NULL // A "Nil" node is just NULL 12 | 13 | // Types 14 | 15 | struct ll_node { 16 | void* item; // pointer to our item (whose type is unknown) 17 | struct ll_node *next; 18 | }; 19 | 20 | // "using" is just like typedef, but it can create template types! 21 | // 22 | typedef struct ll_node* LLNode; // LLNode is a pointer to "struct lst_node" 23 | typedef struct { // LLList is a struct 24 | LLNode dummy; // we use a dummy node, store it here 25 | int item_size; // the size of our items 26 | } LLList; 27 | 28 | typedef int (*LLCompareFunc )(void*, void*); // LLCompareFunc: type of functions that compare two items 29 | typedef void (*LLVisitFunc )(LLList, LLNode); // LLVisitFunc: type of functions that visit a node 30 | 31 | 32 | // Function declarations 33 | 34 | // creates a new list. The item is untyped so we need to know its size! 35 | 36 | LLList LLCreate(int item_size); 37 | 38 | // destroys a list 39 | 40 | void LLDestroy(LLList list); 41 | 42 | // returns the length of a list 43 | 44 | int LLLength(LLList list); 45 | 46 | // returns the node after 'node'. Use node = LL_NIL to get the first. 47 | 48 | LLNode LLNext(LLList list, LLNode node); 49 | 50 | // Returns a pointer to the data 51 | 52 | void *LLGetItem(LLList list, LLNode node); 53 | 54 | // Inserts node after given one and returns it. Use node = LL_NIL to insert as first. 55 | 56 | LLNode LLInsertAfter(LLList list, LLNode node, void *item); 57 | 58 | // Removes a node 59 | 60 | void LLRemove(LLList list, LLNode node); 61 | 62 | // Returns a node that matches the given item (or Nil if not found) 63 | 64 | LLNode LLFind(LLList list, void *item, LLCompareFunc compare); 65 | 66 | // Calls visit(list, node) on every node 67 | 68 | void LLVisit(LLList list, LLVisitFunc visit); 69 | -------------------------------------------------------------------------------- /project3/generic_lists/modules/list_untyped/make.inc: -------------------------------------------------------------------------------- 1 | ifndef LL_MAKE_INC # include guard for make.inc 2 | LL_MAKE_INC=1 3 | 4 | # This file is part of the list module. 5 | # 6 | # Anyone who wants to use the list module should include this file in their 7 | # Makefile, so that compilation is configured properly 8 | # 9 | 10 | # Set compiler flags. -I... tells the compiler to look in our directory for 11 | # include files, so that #include "list.h" works. 12 | # 13 | CFLAGS += -I$(MODULES)/list_untyped 14 | 15 | OBJS += $(MODULES)/list_untyped/list.o 16 | 17 | 18 | endif #include guard 19 | --------------------------------------------------------------------------------