rules_dict = {} terminals_set = set() def parse(lines): lines = [line.strip() for line in lines] lines = [line.split(":") for line in lines] rules = [(line[0].strip(), line[1].strip().split(" ")) for line in lines] for r in rules: for right_element in r[1]: if len(right_element) > 0 and not right_element[0].isupper(): terminals_set.add(right_element) for i in range(0, len(rules)): left = rules[i][0] if left not in rules_dict: rules_dict[left] = 0 print_includes() print_util() print_declarations() print("// ---- Functions to parse terminals ----") print_terminal_rules() print_rules(rules) print_main(rules) # print(rules) # print(rules_dict) # print(terminals_set) def print_declarations(): for key in rules_dict: print(f"int parse_{key}(char* word, int pos);") print() def print_includes(): print("""\ #include #include """) def print_util(): print("""\ void print_with_indent(int indent, char * string) { printf("%*s%s", indent, "", string); } """) # int str_split(char* str, char token) { # char* result = ""; # for (int i = 0; i < sizeof(str); i++) # { # result[ # } # return result; # } def print_main(rules): axiom = get_code(rules[0][0]) print(f"""\ int main(int argc, char* argv[]) {{ char* word; if (argc >= 2) word = argv[1]; else word = ""; int value = parse_{axiom}(word, 0); printf("%d\\n", value); if (value == strlen(word) + 1) {{ printf("OK\\n"); }} else {{ printf("KO\\n"); }} }} """) def print_rules(rules): print("// ---- Functions to parse a non-terminal according to a rule ----") print_unit_rules(rules) print("// ---- Functions to parse a non-terminal by testing all rules ----") print_global_rules() def print_unit_rules(rules): for i in range(0, len(rules)): rule = rules[i] left = rule[0] rules_dict[left] += 1 code = get_code(left) print(f"""\ int parse_{code}{rules_dict[left]}(char* word, int pos) {{ int totalCharParsed = 0; int nbCharParsed; printf("Entering {code}{rules_dict[left]}\\n");""") for element in rule[1]: elem_code = get_code(element) if elem_code != "": print(f""" nbCharParsed = parse_{elem_code}(word, pos + totalCharParsed); if (nbCharParsed == -1) {{ printf("Fail {elem_code} in {code}{rules_dict[left]}\\n"); return -1; }} totalCharParsed += nbCharParsed;""") else: print(f"\n printf(\"Epsilon! -> Success\\n\");") print(f""" printf("Success {code}{rules_dict[left]}\\n"); return totalCharParsed; }} """) def print_global_rules(): for (key, value) in rules_dict.items(): code = get_code(key) print(f"""\ int parse_{code}(char* word, int pos) {{ int nbCharParsed; printf("Entering {key}\\n");""") for i in range(1, value + 1): print(f""" nbCharParsed = parse_{code}{i}(word, pos); if (nbCharParsed != -1) {{ return nbCharParsed; }}""") print(""" return -1; } """) def get_code(s): return ord(s) if len(s) == 1 and ((s < "A" or s > "Z") and (s < "a" or s > "z")) else s def print_terminal_rules(): for t in terminals_set: # escape \ and " in the terminal safeT = "\\" + t if (t == '"' or t == '\\') else t code = get_code(t) l = len(t) print(f"""\ int parse_{code}(char* word, int pos) {{ // Extract the next {l} chars of the word char substr[{l+1}]; substr[0] = '\\0'; strncat(substr, &word[pos], {l}); // Compare this extracted string to the terminal, // and check if the next char is a space or the end of the string if (strcmp(substr, "{safeT}") == 0 && (word[pos+{l}] == ' ' || word[pos+{l}] == '\\0')) {{ print_with_indent(pos, "{safeT}\\n"); return {l+1}; }} else {{ return -1; }} }} """) if __name__ == '__main__': with open("grammar.txt", "r") as f: parse(f.readlines())