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 }