1 // Copyright Mario Kröplin 2021. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // https://www.boost.org/LICENSE_1_0.txt) 5 6 module gamma.main; 7 8 import gamma.grammar.Grammar; 9 import log; 10 import std.range; 11 import std.stdio; 12 13 void main(string[] args) 14 { 15 import core.stdc.stdlib : exit, EXIT_FAILURE, EXIT_SUCCESS; 16 import gamma.grammar.hyper.PrintingHyperVisitor : printingHyperVisitor; 17 import gamma.grammar.Node : Node; 18 import gamma.grammar.PrintingVisitor : printingVisitor; 19 import gamma.grammar.Symbol : Symbol; 20 import gamma.input.epsilang.Analyzer : Analyzer; 21 import gamma.parsgen.lalr1.ParserGrammarBuilder : extendedCfgFromHyperGrammar; 22 import gamma.parsgen.lalr1.PredicateFilter : PredicateFilter; 23 import std.algorithm : map; 24 import std.array : assocArray; 25 import std.datetime.stopwatch : AutoStart, StopWatch; 26 import std.exception : ErrnoException; 27 import std.getopt : defaultGetoptPrinter, getopt, GetoptResult; 28 import std.typecons : tuple; 29 30 GetoptResult result; 31 bool verbose; 32 33 try 34 { 35 result = getopt(args, 36 "verbose|v", "Print debug output.", &verbose, 37 ); 38 } 39 catch (Exception exception) 40 { 41 error!"%s"(exception.msg); 42 exit(EXIT_FAILURE); 43 } 44 if (result.helpWanted) 45 { 46 import std.path : baseName; 47 48 writefln!"Usage: %s [options] <file>..."(args.front.baseName); 49 writeln("Compile each Extended Affix Grammar file into a compiler."); 50 defaultGetoptPrinter("Options:", result.options); 51 exit(EXIT_SUCCESS); 52 } 53 54 if (verbose) 55 levels |= Level.trace; 56 57 try 58 { 59 foreach (arg; args.dropOne) 60 { 61 auto stopWatch = StopWatch(AutoStart.yes); 62 auto input = File(arg); 63 auto analyzer = new Analyzer(input); 64 65 info!"compiling %s"(arg); 66 analyzer.parseSpecification; 67 68 const errorCount = analyzer.getErrorCount; 69 70 switch (errorCount) 71 { 72 case 0: 73 if (auto grammar = analyzer.yieldMetaGrammar) 74 { 75 auto visitor = printingVisitor(stdout.lockingTextWriter); 76 77 visitor.visit(grammar); 78 stdout.writeln; 79 } 80 else 81 stderr.writeln("meta grammar not well defined"); 82 if (auto grammar = analyzer.yieldHyperGrammar) 83 { 84 bool[Symbol] lexicalHyperNonterminals = analyzer.getLexicalHyperNonterminals.byKeyValue 85 .map!(pair => tuple(cast(Symbol) pair.key, pair.value)) 86 .assocArray; 87 auto predicateFilter = new class PredicateFilter 88 { 89 override bool isPredicate(Node node) 90 { 91 return false; 92 } 93 }; 94 auto parserGrammar = grammar 95 .extendedCfgFromHyperGrammar(lexicalHyperNonterminals, predicateFilter); 96 auto visitor = printingHyperVisitor(stdout.lockingTextWriter); 97 98 visitor.visit(parserGrammar); 99 generateParser(parserGrammar); 100 } 101 else 102 stderr.writeln("hyper grammar not well defined"); 103 break; 104 case 1: 105 stderr.writeln("1 error"); 106 break; 107 default: 108 stderr.writeln(errorCount, " errors"); 109 break; 110 } 111 112 stopWatch.stop; 113 stdout.writeln(stopWatch.peek.total!"msecs", " milliseconds"); 114 } 115 } 116 catch (ErrnoException exception) 117 { 118 stderr.writeln(exception.msg); 119 exit(EXIT_FAILURE); 120 } 121 } 122 123 private void generateParser(Grammar grammar) 124 { 125 import gamma.parsgen.lalr1.PennelloDeRemer : PennelloDeRemer; 126 import gamma.parsgen.lalr1.SimpleLR1ConflictResolver : SimpleLR1ConflictResolver; 127 import gamma.parsgen.lalr1.LR1ParserTablesWriter : write; 128 import std.stdio : stdout; 129 130 auto parserGenerator = new PennelloDeRemer; 131 auto conflictResolver = new SimpleLR1ConflictResolver(grammar); 132 auto parserTables = parserGenerator.computeParser(grammar, conflictResolver); 133 134 write(parserTables, stdout); 135 }