MLWCompiler.py 33.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python

#######################################################################
#
# SYMBOLS SECTION - Can be edited. Changes will be preserved.
#
#######################################################################


import os
import sys
eckhart's avatar
eckhart committed
12
import webbrowser
13
from functools import partial
di68kap's avatar
di68kap committed
14
15
16

sys.path.extend(['../', '../../'])

17
18
19
20
try:
    import regex as re
except ImportError:
    import re
21
22
23
24
25
from DHParser import is_filename, Grammar, Compiler, Lookahead, Alternative, Token, Synonym, AllOf, \
    SomeOf, \
    Option, OneOrMore, RegExp, Series, RE, ZeroOrMore, Forward, NegativeLookahead, mixin_comment, \
    compile_source, \
    PreprocessorFunc, \
di68kap's avatar
di68kap committed
26
    Node, TransformationFunc, TransformationDict, \
27
28
29
    traverse, reduce_single_child, replace_by_single_child, replace_or_reduce, remove_whitespace, \
    remove_tokens, flatten, is_expendable, collapse, traverse_locally, remove_nodes, \
    has_content, strip, keep_nodes, remove_anonymous_empty, MockParser
30
from DHParser.log import logging
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


#######################################################################
#
# PREPROCESSOR SECTION - Can be edited. Changes will be preserved.
#
#######################################################################

def MLWPreprocessor(text):
    return text

def get_preprocessor() -> PreprocessorFunc:
    return MLWPreprocessor


#######################################################################
#
# PARSER SECTION - Don't edit! CHANGES WILL BE OVERWRITTEN!
#
#######################################################################

class MLWGrammar(Grammar):
    r"""Parser for a MLW source file, with this grammar:
    
    # EBNF-Syntax für MLW-Artikel
    
di68kap's avatar
di68kap committed
57
58
    # TODO: Vervollständigen!!!!
    
59
    
di68kap's avatar
di68kap committed
60
    @ comment         =  /(?:\/\/.*)|(?:\/\*(?:.|\n)*?\*\/)/   # Kommentare im C++ Stil
61
62
63
64
65
66
67
68
                                          # ohne das Zeilenende zu beinhalten
    @ whitespace      =  /[\t ]*/         # Zeilensprünge zählen nicht als Leerraum
    @ literalws       =  right            # Leerraum vor und nach Literalen wird automatisch entfernt
    
    
    ##############################################################################
    
    Artikel           = [LZ]
di68kap's avatar
di68kap committed
69
70
                        §{ LemmaPosition }+
                        [EtymologiePosition]
71
                        [ArtikelKopf]
di68kap's avatar
di68kap committed
72
73
74
75
                        BedeutungsPosition
                        [VerweisPosition]
                        { UnterArtikel }
                        ArtikelVerfasser
di68kap's avatar
di68kap committed
76
77
                        [Stellenverzeichnis]
                        [LZ] DATEI_ENDE
78
79
80
81
    
    
    #### LEMMA-POSITION ##########################################################
    
di68kap's avatar
di68kap committed
82
83
    LemmaPosition     = [ABS] "LEMMA" [LZ] §Lemma TR [LemmaVarianten]
                        GrammatikPosition [Zusatz]
84
    
di68kap's avatar
di68kap committed
85
    Lemma             = [< klassisch | gesichert >] LemmaWort
86
      klassisch       = "*"
di68kap's avatar
di68kap committed
87
      gesichert       = "$"  # TODO: Noch fragen: Welches Zeichen?
88
    
di68kap's avatar
di68kap committed
89
    LemmaWort         = LAT_WORT
90
    
91
    LemmaVarianten    = LemmaVariante { [";" | ","] [ZW] LemmaVariante } [ [LZ] Zusatz ]
92
    
di68kap's avatar
di68kap committed
93
    LemmaVariante     = LAT_WORT  # Ist eine Lemma immer ein einzelnes Wort?
94
95
96
97
    
    
    ## GRAMMATIK-POSITION ##
    
di68kap's avatar
di68kap committed
98
    GrammatikPosition = ZWW "GRAMMATIK" [LZ] §Grammatik { ABS GrammatikVariante }
di68kap's avatar
di68kap committed
99
    
di68kap's avatar
di68kap committed
100
    Grammatik        = wortart §ABS flexion [[";"] genus]
101
    
eckhart's avatar
eckhart committed
102
103
104
105
106
107
    wortart          = nomen | verb | adverb | adjektiv | praeposition
    nomen            = "nomen"  | "n."
    verb             = "verb"   | "v."
    adverb           = "adverb" | "adv."
    adjektiv         = "adjektiv" | "adj."
    praeposition     = "praeposition" | "praep."
108
    
di68kap's avatar
di68kap committed
109
    flexion          = deklination | konjugation
di68kap's avatar
di68kap committed
110
    deklination      = FLEX ["," FLEX]
di68kap's avatar
di68kap committed
111
    konjugation      = FLEX
112
113
    FLEX             = /-?[a-z]+/~
    
eckhart's avatar
eckhart committed
114
115
116
117
    genus            = maskulinum | femininum | neutrum
    maskulinum       = "maskulinum" | "m."
    femininum        = "femininum" | "f."
    neutrum          = "neutrum" | "n."
118
    
di68kap's avatar
di68kap committed
119
    
di68kap's avatar
di68kap committed
120
    GrammatikVariante  = [wortart ABS] flexion [[";"] genus] DPP Beleg { FORTSETZUNG Beleg }   # Beleg { SEM Beleg }
di68kap's avatar
di68kap committed
121
    
122
123
    
    
di68kap's avatar
di68kap committed
124
125
    #### ETYMOLOGIE-POSITION #####################################################
    
di68kap's avatar
di68kap committed
126
    EtymologiePosition = ZWW "ETYMOLOGIE" [LZ] { EtymologieVariante }+
127
    EtymologieVariante = (LAT | GRI) [EtymologieBesonderheit] [DPP [LZ] Etymologie] DPP Beleg
di68kap's avatar
di68kap committed
128
129
    EtymologieBesonderheit = EINZEILER
    Etymologie         = EINZEILER
di68kap's avatar
di68kap committed
130
    
131
132
133
    
    #### ARTIKEL-KOPF ############################################################
    
di68kap's avatar
di68kap committed
134
135
    ArtikelKopf     = <   SchreibweisenPosition
                        | StrukturPosition
di68kap's avatar
di68kap committed
136
                        | GebrauchsPosition
di68kap's avatar
di68kap committed
137
                        | MetrikPosition
di68kap's avatar
di68kap committed
138
                        | VerwechselungsPosition >
di68kap's avatar
di68kap committed
139
    
di68kap's avatar
di68kap committed
140
141
    SchreibweisenPosition = ZWW "SCHREIBWEISE"  Position
    StrukturPosition      = ZWW "STRUKTUR"      Position
di68kap's avatar
di68kap committed
142
    GebrauchsPosition     = ZWW "GEBRAUCH"      Position
di68kap's avatar
di68kap committed
143
    MetrikPosition        = ZWW "METRIK"        Position
di68kap's avatar
di68kap committed
144
    VerwechselungsPosition = ZWW "VERWECHSELBAR" Position
di68kap's avatar
di68kap committed
145
    
di68kap's avatar
di68kap committed
146
    ## ARTIKELKOPF POSITIONEN ##
di68kap's avatar
di68kap committed
147
    
148
    Position       = [LZ] §(Kategorien | Besonderheiten)
di68kap's avatar
di68kap committed
149
    Kategorien     = Kategorie { ZWW Kategorie }
150
151
152
    Kategorie      = Beschreibung DPP [LZ] Besonderheiten
    Besonderheiten = Besonderheit { ZWW Besonderheit }
    Besonderheit   = Beschreibung DPP [LZ] Varianten
di68kap's avatar
di68kap committed
153
    Varianten      = Variante { ZWW Variante }
154
155
    Variante       = !KATEGORIENZEILE Beschreibung DPP Belege
    Beschreibung   = EINZEILER
156
157
158
159
    
    
    #### BEDEUTUNGS-POSITION #####################################################
    
di68kap's avatar
di68kap committed
160
    BedeutungsPosition   = { ZWW "BEDEUTUNG" [LZ] §Bedeutung [U1Bedeutung] }+
di68kap's avatar
di68kap committed
161
162
    U1Bedeutung          = { ZWW ("U_BEDEUTUNG" | "UNTER_BEDEUTUNG") [LZ] §Bedeutung [U2Bedeutung] }+
    U2Bedeutung          = { ZWW ("UU_BEDEUTUNG" | "UNTER_UNTER_BEDEUTUNG") [LZ] §Bedeutung [U3Bedeutung] }+
163
164
165
    U3Bedeutung          = { ZWW "UUU_BEDEUTUNG" [LZ] §Bedeutung [U4Bedeutung] }+
    U4Bedeutung          = { ZWW "UUUU_BEDEUTUNG" [LZ] §Bedeutung [U5Bedeutung] }+
    U5Bedeutung          = { ZWW "UUUUU_BEDEUTUNG" [LZ] §UntersteBedeutung }+
166
    
di68kap's avatar
di68kap committed
167
    Bedeutung            = (Interpretamente | Bedeutungskategorie) [BelegPosition]
di68kap's avatar
di68kap committed
168
    UntersteBedeutung    = Interpretamente [BelegPosition]
169
    Bedeutungskategorie  = { EINZEILER [LZ] [Zusatz] [LZ] } §":"
170
171
    
    Interpretamente      = LateinischeBedeutung (LZ | " " | "--") §DeutscheBedeutung [":"]
di68kap's avatar
di68kap committed
172
173
    LateinischeBedeutung = LAT [ZW] LateinischerAusdruck { "," [ZW] LateinischerAusdruck }
    DeutscheBedeutung    = DEU [ZW] DeutscherAusdruck { "," [ZW] DeutscherAusdruck }
174
175
176
177
    LateinischerAusdruck = { <LateinischesWort [Zusatz]> }+
    DeutscherAusdruck    = { <DeutschesWort [Zusatz]> }+
    LateinischesWort     = (LAT_WORT | "(" { LAT_WORT }+ ")")
    DeutschesWort        = (DEU_WORT | "(" { DEU_WORT }+ ")")
178
179
180
181
182
    
    LAT = "LATEINISCH" | "LAT"
    DEU = "DEUTSCH" | "DEU"
    GRI = "GRIECHISCH" | "GRIECH" | "GRIE" | "GRI"
    
183
    
di68kap's avatar
di68kap committed
184
    BelegPosition = ZWW ["BELEGE" [LZ]] Belege
di68kap's avatar
di68kap committed
185
186
    
    
di68kap's avatar
di68kap committed
187
    #### VERWEIS-POSITION ########################################################
188
    
di68kap's avatar
di68kap committed
189
    VerweisPosition = ZWW "VERWEISE"
di68kap's avatar
di68kap committed
190
191
    
    
di68kap's avatar
di68kap committed
192
    #### UNTER-ARTIKEL ###########################################################
di68kap's avatar
di68kap committed
193
    
di68kap's avatar
di68kap committed
194
    UnterArtikel = ZWW "UNTER-ARTIKEL"
195
196
197
198
    
    
    #### AUTOR/AUTORIN ###########################################################
    
199
    ArtikelVerfasser = ZWW ("AUTORIN" | "AUTOR") §Name
di68kap's avatar
di68kap committed
200
201
    Name             = { NAME | NAMENS_ABKÜRZUNG | unbekannt }+
    unbekannt        = "unbekannt"
202
    
di68kap's avatar
di68kap committed
203
    #### STELLENVERZEICHNIS ######################################################
di68kap's avatar
di68kap committed
204
    
di68kap's avatar
di68kap committed
205
206
207
208
    Stellenverzeichnis = ZWW "STELLENVERZEICHNIS" [LemmaWort] ZWW Verweisliste
    Verweisliste       = { [LZ] "*" Stellenverweis }
    Stellenverweis     = BelegQuelle { [ABS] Stelle (NullVerweis | Verweis) }
    NullVerweis        = "{" "-" "}"
di68kap's avatar
di68kap committed
209
    
di68kap's avatar
di68kap committed
210
211
    
    #### ZUSATZ an verschiedenen Stellen der Struktur ############################
212
    
di68kap's avatar
di68kap committed
213
    Zusatz       = { "{" !("=>" | "@" | "^") §EinzelnerZusatz { ";;" EinzelnerZusatz } "}" }+  # mehrteilige Zusätze unnötig
di68kap's avatar
di68kap committed
214
      EinzelnerZusatz  = FesterZusatz | GemischterZusatz | FreierZusatz
eckhart's avatar
eckhart committed
215
216
217
218
      FesterZusatz     = adde | saepe | persaepe
        adde     = "adde"
        saepe    = "saepe"
        persaepe = "persaepe"
di68kap's avatar
di68kap committed
219
220
221
      GemischterZusatz = ( GebrauchsHinweis | PlurSingHinweis ) FreierZusatz
      GebrauchsHinweis = "usu"
      PlurSingHinweis  = "plur. sensu sing."
di68kap's avatar
di68kap committed
222
      FreierZusatz     = { FREITEXT | VerweisKern | Verweis }+
di68kap's avatar
di68kap committed
223
224
225
226
    
    
    #### BELEGE ##################################################################
    
227
228
    Belege           = ["*"] Beleg { [LZ] (SonderBelege | "*" Beleg) }
    SonderBelege     = "**" Beleg { [LZ] "**" Beleg }
di68kap's avatar
di68kap committed
229
    Beleg            = [Zusatz] ((Verweis [Zitat]) | Zitat) [ABS Zusatz] ["."]
230
    Zitat            = Quellenangabe { SEM [ZW] BelegStelle }
di68kap's avatar
di68kap committed
231
    Quellenangabe    = [<Anker | Zusatz>] < BelegQuelle | Verweis >
di68kap's avatar
di68kap committed
232
    BelegQuelle      = AutorWerk &SEM
233
    BelegStelle      = [<Anker | Zusatz>] (Stelle [[ZW] BelegText] | Verweis) [[ZW] Zusatz]
di68kap's avatar
di68kap committed
234
    BelegText        = /"/ { MEHRZEILER | Anker | Zusatz } §/"/~ ["."]
di68kap's avatar
di68kap committed
235
    
di68kap's avatar
di68kap committed
236
    AutorWerk = EINZEILER
di68kap's avatar
di68kap committed
237
    Stelle    = EINZEILER
di68kap's avatar
di68kap committed
238
239
    
    
di68kap's avatar
di68kap committed
240
241
242
    #### VERWEISE (LINKS) ########################################################
    
    Verweis          = "{" VerweisKern "}"
di68kap's avatar
di68kap committed
243
    VerweisKern      = "=>" §((alias "|" ("-" | URL)) | URL)
di68kap's avatar
di68kap committed
244
    Anker            = "{" "@" §ziel "}"
di68kap's avatar
di68kap committed
245
246
    # URL              = [ ([protokoll] domäne /\//) | /\// ] { pfad /\// } ziel
    URL              = [protokoll] [/\//] { pfad /\// } ziel
di68kap's avatar
di68kap committed
247
248
249
    
    alias            = FREITEXT
    protokoll        = /\w+:\/\//
di68kap's avatar
di68kap committed
250
251
252
253
254
    # domäne           = /\w+\.\w+(?:\.\w+)*/
    pfad             = PFAD_NAME # /\w+/
    ziel             = PFAD_NAME # /[\w=?.%&\[\] ]+/
    
    
di68kap's avatar
di68kap committed
255
256
    #### GENERISCHE UND ATOMARE AUSDRÜCKE ########################################
    
di68kap's avatar
di68kap committed
257
258
    PFAD_NAME        = /[\w=?.%&\[\] ]+/
    
259
260
261
    NAMENS_ABKÜRZUNG = /[A-ZÄÖÜÁÀÂÓÒÔÚÙÛ]\./~
    NAME             = /[A-ZÄÖÜÁÀÓÒÚÙÂÔÛ][a-zäöüßáàâóòôúùû]+/~
    
di68kap's avatar
di68kap committed
262
    DEU_WORT         = DEU_GROSS | DEU_KLEIN | GROSSBUCHSTABE
di68kap's avatar
di68kap committed
263
    DEU_GROSS        = /[A-ZÄÖÜ][a-zäöüßę_\-.]+/~
di68kap's avatar
di68kap committed
264
265
    GROSSBUCHSTABE   = /[A-ZÄÖÜ](?=[ \t\n])/~
    KLEINBUCHSTABE   = /[a-zäöü](?=[ \t\n])/~
di68kap's avatar
di68kap committed
266
    GRI_BUCHSTABE    = /[αβγδεζηθικλμνξοπρςστυφχψω]/
di68kap's avatar
di68kap committed
267
268
269
    DEU_KLEIN        = /(?!--)[a-zäöüßęõ_\-.]+/~
    LAT_WORT         = /(?!--)[a-z|\-_.]+/~
    GROSSSCHRIFT     = /(?!--)[A-ZÄÖÜ_\-]+/~
di68kap's avatar
di68kap committed
270
    ZAHL             = /[\d]+/~
di68kap's avatar
di68kap committed
271
    SEITENZAHL       = /[\d]+(?:\^(?:(?:\{[\d\w.,!? ]+\})|[\d\w.]+))?/~     # Zahl mit optionale folgendem hochgestelltem Buchstaben oder Text
di68kap's avatar
di68kap committed
272
    ROEMISCHE_ZAHL   = /(?=[MDCLXVI])M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)(?=[^\w])/~
273
    SCHLUESSELWORT   = { //~ /\n/ }+ !ROEMISCHE_ZAHL /[A-ZÄÖÜ]{3,}\s+/
di68kap's avatar
di68kap committed
274
    
di68kap's avatar
di68kap committed
275
276
    SATZZEICHEN      = /(?!->)(?:(?:,(?!,))|(?:;(?!;))|(?::(?!:))|(?:-(?!-))|[.()\[\]]+)|[`''‘’?]/~  # div. Satzzeichen, aber keine doppelten ,, ;; oder ::
    TEIL_SATZZEICHEN = /(?!->)(?:(?:,(?!,))|(?:-(?!-))|[.()]+)|[`''‘’?]/~ # Satzeichen bis auf Doppelpunkt ":", Semikolon ";" und eckige Klammern
di68kap's avatar
di68kap committed
277
    
278
279
    BUCHSTABENFOLGE  = /\w+/~
    ZEICHENFOLGE     = /[\w()-]+/~
di68kap's avatar
di68kap committed
280
    TEXTELEMENT      = DEU_WORT | SEITENZAHL | ROEMISCHE_ZAHL
di68kap's avatar
di68kap committed
281
    EINZEILER        = { TEXTELEMENT | TEIL_SATZZEICHEN }+
di68kap's avatar
di68kap committed
282
    FREITEXT         = { TEXTELEMENT | SATZZEICHEN | GROSSSCHRIFT }+
di68kap's avatar
di68kap committed
283
    MEHRZEILER       = { FREITEXT | /\s+(?=[\w,;:.\(\)\-])/ | /\n\s*/ }+
284
    
di68kap's avatar
di68kap committed
285
    TR               = ABS | LZ                  # (beliebiger) Trenner
di68kap's avatar
di68kap committed
286
    ABS              = /\s*;;?\s*/ | ZWW         # Abschluss (durch Semikolon oder Zeilenwechsel)
di68kap's avatar
di68kap committed
287
    # ZW               = /\n/~                   # Zeilenwechsel
di68kap's avatar
di68kap committed
288
    LZ               = { COMMENT__ | /\s+/ }+    # Leerzeichen oder -zeilen
di68kap's avatar
di68kap committed
289
290
    DPP              = /::?/~                    # Doppelpunkt als Trenner
    SEM              = /;;?/~                    # Semikolon als Trenner
291
292
    
    ZW               = !LÜCKE ZEILENSPRUNG       # Zeilenwechsel, aber keine Leerzeile(n)
di68kap's avatar
di68kap committed
293
294
    ZWW              = ZEILENSPRUNG [ LZ ]       # mindestens ein Zeilenwechsel
    LÜCKE            = KOMMENTARZEILEN LEERZEILE [LZ] # Leerraum mit mindestens einer echten Leerzeile
295
296
297
298
299
    LEERZEILE        = /[ \t]*(?:\n[ \t]*)+\n/ ~/\n?/ # eine oder mehrere echte LEERZEILEN
    RZS              = /\s*?\n|$/               # Rückwärtiger Zeilensprung oder Textanfang
    
    ZEILENSPRUNG     = /[ \t]*\n/~
    KOMMENTARZEILEN  = { /[ \t]*\n?[ \t]*/ COMMENT__ }  # echte Kommentarzeilen
di68kap's avatar
di68kap committed
300
    KATEGORIENZEILE  = /[^:\n]+[:][ \t]*\n/     # Kategorienzeilen enthalten genau einen Doppelpunkt am Ende der Zeile
301
    FORTSETZUNG      = !(ZWW /[^:\n]+[:]/)
302
303
304
305
    
    DATEI_ENDE       = !/./
    NIEMALS          = /(?!.)/
    """
di68kap's avatar
di68kap committed
306
    DEU_WORT = Forward()
di68kap's avatar
di68kap committed
307
308
    FREITEXT = Forward()
    GROSSSCHRIFT = Forward()
di68kap's avatar
di68kap committed
309
    LZ = Forward()
di68kap's avatar
di68kap committed
310
    LemmaWort = Forward()
di68kap's avatar
di68kap committed
311
312
    ROEMISCHE_ZAHL = Forward()
    SATZZEICHEN = Forward()
di68kap's avatar
di68kap committed
313
    SEITENZAHL = Forward()
di68kap's avatar
di68kap committed
314
    TEIL_SATZZEICHEN = Forward()
di68kap's avatar
di68kap committed
315
    TEXTELEMENT = Forward()
316
    ZWW = Forward()
di68kap's avatar
di68kap committed
317
    Zusatz = Forward()
di68kap's avatar
di68kap committed
318
319
    flexion = Forward()
    genus = Forward()
320
    wortart = Forward()
321
    source_hash__ = "17e7d9c6b771eb2fa259912b687f8677"
322
    parser_initialization__ = "upon instantiation"
di68kap's avatar
di68kap committed
323
    COMMENT__ = r'(?:\/\/.*)|(?:\/\*(?:.|\n)*?\*\/)'
324
325
326
327
328
329
    WHITESPACE__ = r'[\t ]*'
    WSP__ = mixin_comment(whitespace=WHITESPACE__, comment=COMMENT__)
    wspL__ = ''
    wspR__ = WSP__
    NIEMALS = RegExp('(?!.)')
    DATEI_ENDE = NegativeLookahead(RegExp('.'))
330
    FORTSETZUNG = NegativeLookahead(Series(ZWW, RegExp('[^:\\n]+[:]')))
di68kap's avatar
di68kap committed
331
    KATEGORIENZEILE = RegExp('[^:\\n]+[:][ \\t]*\\n')
332
333
334
335
    KOMMENTARZEILEN = ZeroOrMore(Series(RegExp('[ \\t]*\\n?[ \\t]*'), RegExp(COMMENT__)))
    ZEILENSPRUNG = RE('[ \\t]*\\n')
    RZS = RegExp('\\s*?\\n|$')
    LEERZEILE = Series(RegExp('[ \\t]*(?:\\n[ \\t]*)+\\n'), RE('\\n?', wR='', wL=WSP__))
di68kap's avatar
di68kap committed
336
337
    LÜCKE = Series(KOMMENTARZEILEN, LEERZEILE, Option(LZ))
    ZWW.set(Series(ZEILENSPRUNG, Option(LZ)))
338
    ZW = Series(NegativeLookahead(LÜCKE), ZEILENSPRUNG)
di68kap's avatar
di68kap committed
339
340
    SEM = RE(';;?')
    DPP = RE('::?')
di68kap's avatar
di68kap committed
341
    LZ.set(OneOrMore(Alternative(RegExp(COMMENT__), RegExp('\\s+'))))
di68kap's avatar
di68kap committed
342
    ABS = Alternative(RegExp('\\s*;;?\\s*'), ZWW)
343
    TR = Alternative(ABS, LZ)
di68kap's avatar
di68kap committed
344
    MEHRZEILER = OneOrMore(Alternative(FREITEXT, RegExp('\\s+(?=[\\w,;:.\\(\\)\\-])'), RegExp('\\n\\s*')))
di68kap's avatar
di68kap committed
345
    FREITEXT.set(OneOrMore(Alternative(TEXTELEMENT, SATZZEICHEN, GROSSSCHRIFT)))
di68kap's avatar
di68kap committed
346
    EINZEILER = OneOrMore(Alternative(TEXTELEMENT, TEIL_SATZZEICHEN))
di68kap's avatar
di68kap committed
347
    TEXTELEMENT.set(Alternative(DEU_WORT, SEITENZAHL, ROEMISCHE_ZAHL))
348
349
    ZEICHENFOLGE = RE('[\\w()-]+')
    BUCHSTABENFOLGE = RE('\\w+')
di68kap's avatar
di68kap committed
350
351
    TEIL_SATZZEICHEN.set(RE("(?!->)(?:(?:,(?!,))|(?:-(?!-))|[.()]+)|[`''‘’?]"))
    SATZZEICHEN.set(RE("(?!->)(?:(?:,(?!,))|(?:;(?!;))|(?::(?!:))|(?:-(?!-))|[.()\\[\\]]+)|[`''‘’?]"))
352
    SCHLUESSELWORT = Series(OneOrMore(Series(RE(''), RegExp('\\n'))), NegativeLookahead(ROEMISCHE_ZAHL), RegExp('[A-ZÄÖÜ]{3,}\\s+'))
di68kap's avatar
di68kap committed
353
    ROEMISCHE_ZAHL.set(RE('(?=[MDCLXVI])M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)(?=[^\\w])'))
di68kap's avatar
di68kap committed
354
    SEITENZAHL.set(RE('[\\d]+(?:\\^(?:(?:\\{[\\d\\w.,!? ]+\\})|[\\d\\w.]+))?'))
di68kap's avatar
di68kap committed
355
    ZAHL = RE('[\\d]+')
di68kap's avatar
di68kap committed
356
    GROSSSCHRIFT.set(RE('(?!--)[A-ZÄÖÜ_\\-]+'))
357
    LAT_WORT = RE('(?!--)[a-z|\\-_.]+')
di68kap's avatar
di68kap committed
358
    DEU_KLEIN = RE('(?!--)[a-zäöüßęõ_\\-.]+')
di68kap's avatar
di68kap committed
359
    GRI_BUCHSTABE = RegExp('[αβγδεζηθικλμνξοπρςστυφχψω]')
di68kap's avatar
di68kap committed
360
361
    KLEINBUCHSTABE = RE('[a-zäöü](?=[ \\t\\n])')
    GROSSBUCHSTABE = RE('[A-ZÄÖÜ](?=[ \\t\\n])')
di68kap's avatar
di68kap committed
362
    DEU_GROSS = RE('[A-ZÄÖÜ][a-zäöüßę_\\-.]+')
di68kap's avatar
di68kap committed
363
    DEU_WORT.set(Alternative(DEU_GROSS, DEU_KLEIN, GROSSBUCHSTABE))
364
365
    NAME = RE('[A-ZÄÖÜÁÀÓÒÚÙÂÔÛ][a-zäöüßáàâóòôúùû]+')
    NAMENS_ABKÜRZUNG = RE('[A-ZÄÖÜÁÀÂÓÒÔÚÙÛ]\\.')
di68kap's avatar
di68kap committed
366
367
368
    PFAD_NAME = RegExp('[\\w=?.%&\\[\\] ]+')
    ziel = Synonym(PFAD_NAME)
    pfad = Synonym(PFAD_NAME)
di68kap's avatar
di68kap committed
369
370
    protokoll = RegExp('\\w+://')
    alias = Synonym(FREITEXT)
di68kap's avatar
di68kap committed
371
    URL = Series(Option(protokoll), Option(RegExp('/')), ZeroOrMore(Series(pfad, RegExp('/'))), ziel)
di68kap's avatar
di68kap committed
372
    Anker = Series(Token("{"), Token("@"), ziel, Token("}"), mandatory=2)
di68kap's avatar
di68kap committed
373
    VerweisKern = Series(Token("=>"), Alternative(Series(alias, Token("|"), Alternative(Token("-"), URL)), URL), mandatory=1)
di68kap's avatar
di68kap committed
374
    Verweis = Series(Token("{"), VerweisKern, Token("}"))
di68kap's avatar
di68kap committed
375
    Stelle = Synonym(EINZEILER)
di68kap's avatar
di68kap committed
376
    AutorWerk = Synonym(EINZEILER)
di68kap's avatar
di68kap committed
377
    BelegText = Series(RegExp('"'), ZeroOrMore(Alternative(MEHRZEILER, Anker, Zusatz)), RE('"'), Option(Token(".")), mandatory=2)
378
    BelegStelle = Series(Option(SomeOf(Anker, Zusatz)), Alternative(Series(Stelle, Option(Series(Option(ZW), BelegText))), Verweis), Option(Series(Option(ZW), Zusatz)))
di68kap's avatar
di68kap committed
379
    BelegQuelle = Series(AutorWerk, Lookahead(SEM))
di68kap's avatar
di68kap committed
380
    Quellenangabe = Series(Option(SomeOf(Anker, Zusatz)), SomeOf(BelegQuelle, Verweis))
381
    Zitat = Series(Quellenangabe, ZeroOrMore(Series(SEM, Option(ZW), BelegStelle)))
di68kap's avatar
di68kap committed
382
    Beleg = Series(Option(Zusatz), Alternative(Series(Verweis, Option(Zitat)), Zitat), Option(Series(ABS, Zusatz)), Option(Token(".")))
383
384
    SonderBelege = Series(Token("**"), Beleg, ZeroOrMore(Series(Option(LZ), Token("**"), Beleg)))
    Belege = Series(Option(Token("*")), Beleg, ZeroOrMore(Series(Option(LZ), Alternative(SonderBelege, Series(Token("*"), Beleg)))))
di68kap's avatar
di68kap committed
385
    FreierZusatz = OneOrMore(Alternative(FREITEXT, VerweisKern, Verweis))
di68kap's avatar
di68kap committed
386
387
388
    PlurSingHinweis = Token("plur. sensu sing.")
    GebrauchsHinweis = Token("usu")
    GemischterZusatz = Series(Alternative(GebrauchsHinweis, PlurSingHinweis), FreierZusatz)
eckhart's avatar
eckhart committed
389
390
391
392
    persaepe = Token("persaepe")
    saepe = Token("saepe")
    adde = Token("adde")
    FesterZusatz = Alternative(adde, saepe, persaepe)
di68kap's avatar
di68kap committed
393
    EinzelnerZusatz = Alternative(FesterZusatz, GemischterZusatz, FreierZusatz)
di68kap's avatar
di68kap committed
394
    Zusatz.set(OneOrMore(Series(Token("{"), NegativeLookahead(Alternative(Token("=>"), Token("@"), Token("^"))), EinzelnerZusatz, ZeroOrMore(Series(Token(";;"), EinzelnerZusatz)), Token("}"), mandatory=2)))
di68kap's avatar
di68kap committed
395
396
397
398
    NullVerweis = Series(Token("{"), Token("-"), Token("}"))
    Stellenverweis = Series(BelegQuelle, ZeroOrMore(Series(Option(ABS), Stelle, Alternative(NullVerweis, Verweis))))
    Verweisliste = ZeroOrMore(Series(Option(LZ), Token("*"), Stellenverweis))
    Stellenverzeichnis = Series(ZWW, Token("STELLENVERZEICHNIS"), Option(LemmaWort), ZWW, Verweisliste)
di68kap's avatar
di68kap committed
399
400
    unbekannt = Token("unbekannt")
    Name = OneOrMore(Alternative(NAME, NAMENS_ABKÜRZUNG, unbekannt))
401
    ArtikelVerfasser = Series(ZWW, Alternative(Token("AUTORIN"), Token("AUTOR")), Name, mandatory=2)
di68kap's avatar
di68kap committed
402
403
    UnterArtikel = Series(ZWW, Token("UNTER-ARTIKEL"))
    VerweisPosition = Series(ZWW, Token("VERWEISE"))
di68kap's avatar
di68kap committed
404
    BelegPosition = Series(ZWW, Option(Series(Token("BELEGE"), Option(LZ))), Belege)
405
406
407
    GRI = Alternative(Token("GRIECHISCH"), Token("GRIECH"), Token("GRIE"), Token("GRI"))
    DEU = Alternative(Token("DEUTSCH"), Token("DEU"))
    LAT = Alternative(Token("LATEINISCH"), Token("LAT"))
408
409
410
411
    DeutschesWort = Alternative(DEU_WORT, Series(Token("("), OneOrMore(DEU_WORT), Token(")")))
    LateinischesWort = Alternative(LAT_WORT, Series(Token("("), OneOrMore(LAT_WORT), Token(")")))
    DeutscherAusdruck = OneOrMore(AllOf(DeutschesWort, Option(Zusatz)))
    LateinischerAusdruck = OneOrMore(AllOf(LateinischesWort, Option(Zusatz)))
di68kap's avatar
di68kap committed
412
413
    DeutscheBedeutung = Series(DEU, Option(ZW), DeutscherAusdruck, ZeroOrMore(Series(Token(","), Option(ZW), DeutscherAusdruck)))
    LateinischeBedeutung = Series(LAT, Option(ZW), LateinischerAusdruck, ZeroOrMore(Series(Token(","), Option(ZW), LateinischerAusdruck)))
414
    Interpretamente = Series(LateinischeBedeutung, Alternative(LZ, Token(" "), Token("--")), DeutscheBedeutung, Option(Token(":")), mandatory=2)
415
    Bedeutungskategorie = Series(ZeroOrMore(Series(EINZEILER, Option(LZ), Option(Zusatz), Option(LZ))), Token(":"), mandatory=1)
di68kap's avatar
di68kap committed
416
    UntersteBedeutung = Series(Interpretamente, Option(BelegPosition))
di68kap's avatar
di68kap committed
417
    Bedeutung = Series(Alternative(Interpretamente, Bedeutungskategorie), Option(BelegPosition))
418
419
420
    U5Bedeutung = OneOrMore(Series(ZWW, Token("UUUUU_BEDEUTUNG"), Option(LZ), UntersteBedeutung, mandatory=3))
    U4Bedeutung = OneOrMore(Series(ZWW, Token("UUUU_BEDEUTUNG"), Option(LZ), Bedeutung, Option(U5Bedeutung), mandatory=3))
    U3Bedeutung = OneOrMore(Series(ZWW, Token("UUU_BEDEUTUNG"), Option(LZ), Bedeutung, Option(U4Bedeutung), mandatory=3))
di68kap's avatar
di68kap committed
421
422
    U2Bedeutung = OneOrMore(Series(ZWW, Alternative(Token("UU_BEDEUTUNG"), Token("UNTER_UNTER_BEDEUTUNG")), Option(LZ), Bedeutung, Option(U3Bedeutung), mandatory=3))
    U1Bedeutung = OneOrMore(Series(ZWW, Alternative(Token("U_BEDEUTUNG"), Token("UNTER_BEDEUTUNG")), Option(LZ), Bedeutung, Option(U2Bedeutung), mandatory=3))
di68kap's avatar
di68kap committed
423
    BedeutungsPosition = OneOrMore(Series(ZWW, Token("BEDEUTUNG"), Option(LZ), Bedeutung, Option(U1Bedeutung), mandatory=3))
424
425
    Beschreibung = Synonym(EINZEILER)
    Variante = Series(NegativeLookahead(KATEGORIENZEILE), Beschreibung, DPP, Belege)
di68kap's avatar
di68kap committed
426
    Varianten = Series(Variante, ZeroOrMore(Series(ZWW, Variante)))
427
428
429
430
431
    Besonderheit = Series(Beschreibung, DPP, Option(LZ), Varianten)
    Besonderheiten = Series(Besonderheit, ZeroOrMore(Series(ZWW, Besonderheit)))
    Kategorie = Series(Beschreibung, DPP, Option(LZ), Besonderheiten)
    Kategorien = Series(Kategorie, ZeroOrMore(Series(ZWW, Kategorie)))
    Position = Series(Option(LZ), Alternative(Kategorien, Besonderheiten), mandatory=1)
di68kap's avatar
di68kap committed
432
    VerwechselungsPosition = Series(ZWW, Token("VERWECHSELBAR"), Position)
di68kap's avatar
di68kap committed
433
    MetrikPosition = Series(ZWW, Token("METRIK"), Position)
di68kap's avatar
di68kap committed
434
    GebrauchsPosition = Series(ZWW, Token("GEBRAUCH"), Position)
di68kap's avatar
di68kap committed
435
436
    StrukturPosition = Series(ZWW, Token("STRUKTUR"), Position)
    SchreibweisenPosition = Series(ZWW, Token("SCHREIBWEISE"), Position)
di68kap's avatar
di68kap committed
437
    ArtikelKopf = SomeOf(SchreibweisenPosition, StrukturPosition, GebrauchsPosition, MetrikPosition, VerwechselungsPosition)
di68kap's avatar
di68kap committed
438
439
    Etymologie = Synonym(EINZEILER)
    EtymologieBesonderheit = Synonym(EINZEILER)
Eckhart Arnold's avatar
Eckhart Arnold committed
440
    EtymologieVariante = Series(Alternative(LAT, GRI), Option(EtymologieBesonderheit), Option(Series(DPP, Option(LZ), Etymologie)), DPP, Beleg)
di68kap's avatar
di68kap committed
441
    EtymologiePosition = Series(ZWW, Token("ETYMOLOGIE"), Option(LZ), OneOrMore(EtymologieVariante))
di68kap's avatar
di68kap committed
442
    GrammatikVariante = Series(Option(Series(wortart, ABS)), flexion, Option(Series(Option(Token(";")), genus)), DPP, Beleg, ZeroOrMore(Series(FORTSETZUNG, Beleg)))
eckhart's avatar
eckhart committed
443
444
445
446
    neutrum = Alternative(Token("neutrum"), Token("n."))
    femininum = Alternative(Token("femininum"), Token("f."))
    maskulinum = Alternative(Token("maskulinum"), Token("m."))
    genus.set(Alternative(maskulinum, femininum, neutrum))
447
    FLEX = RE('-?[a-z]+')
di68kap's avatar
di68kap committed
448
    konjugation = Synonym(FLEX)
di68kap's avatar
di68kap committed
449
    deklination = Series(FLEX, Option(Series(Token(","), FLEX)))
di68kap's avatar
di68kap committed
450
    flexion.set(Alternative(deklination, konjugation))
eckhart's avatar
eckhart committed
451
452
453
454
455
456
    praeposition = Alternative(Token("praeposition"), Token("praep."))
    adjektiv = Alternative(Token("adjektiv"), Token("adj."))
    adverb = Alternative(Token("adverb"), Token("adv."))
    verb = Alternative(Token("verb"), Token("v."))
    nomen = Alternative(Token("nomen"), Token("n."))
    wortart.set(Alternative(nomen, verb, adverb, adjektiv, praeposition))
di68kap's avatar
di68kap committed
457
    Grammatik = Series(wortart, ABS, flexion, Option(Series(Option(Token(";")), genus)), mandatory=1)
di68kap's avatar
di68kap committed
458
    GrammatikPosition = Series(ZWW, Token("GRAMMATIK"), Option(LZ), Grammatik, ZeroOrMore(Series(ABS, GrammatikVariante)), mandatory=3)
di68kap's avatar
di68kap committed
459
    LemmaVariante = Synonym(LAT_WORT)
460
    LemmaVarianten = Series(LemmaVariante, ZeroOrMore(Series(Option(Alternative(Token(";"), Token(","))), Option(ZW), LemmaVariante)), Option(Series(Option(LZ), Zusatz)))
di68kap's avatar
di68kap committed
461
    LemmaWort.set(Synonym(LAT_WORT))
462
463
    gesichert = Token("$")
    klassisch = Token("*")
di68kap's avatar
di68kap committed
464
    Lemma = Series(Option(SomeOf(klassisch, gesichert)), LemmaWort)
di68kap's avatar
di68kap committed
465
    LemmaPosition = Series(Option(ABS), Token("LEMMA"), Option(LZ), Lemma, TR, Option(LemmaVarianten), GrammatikPosition, Option(Zusatz), mandatory=3)
di68kap's avatar
di68kap committed
466
    Artikel = Series(Option(LZ), OneOrMore(LemmaPosition), Option(EtymologiePosition), Option(ArtikelKopf), BedeutungsPosition, Option(VerweisPosition), ZeroOrMore(UnterArtikel), ArtikelVerfasser, Option(Stellenverzeichnis), Option(LZ), DATEI_ENDE, mandatory=1)
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
    root__ = Artikel
    
def get_grammar() -> MLWGrammar:
    global thread_local_MLW_grammar_singleton
    try:
        grammar = thread_local_MLW_grammar_singleton
    except NameError:
        thread_local_MLW_grammar_singleton = MLWGrammar()
        grammar = thread_local_MLW_grammar_singleton
    return grammar


#######################################################################
#
# AST SECTION - Can be edited. Changes will be preserved.
#
#######################################################################

485
486
487
488
489
LemmaVariante_table = {
    "LAT_WORT, DEU_WORT": [remove_whitespace, reduce_single_child],
    "Zusatz": [reduce_single_child]
}

di68kap's avatar
di68kap committed
490
491
492
def content_from_parser_name(context):
    assert not context[-1].result
    context[-1].result = context[-1].tag_name
eckhart's avatar
eckhart committed
493

494
495
MLW_AST_transformation_table = {
    # AST Transformations for the MLW-grammar
di68kap's avatar
di68kap committed
496
497
    "+": [remove_anonymous_empty, remove_nodes('ZWW', 'ZW', 'LZ', 'DPP', 'COMMENT__', 'ABS', 'SEM', 'TR'),
          remove_tokens(":")],
498
    "AutorWerk": [reduce_single_child],
499
    "Artikel": [],
di68kap's avatar
di68kap committed
500
    "LemmaPosition": [],
501
    "Lemma": [],
502
503
    "klassisch": [reduce_single_child],
    "gesichert": [reduce_single_child],
di68kap's avatar
di68kap committed
504
    "LemmaWort": [reduce_single_child],
505
    "LemmaVariante": [reduce_single_child, traverse_locally(LemmaVariante_table)],
eckhart's avatar
eckhart committed
506
    "LemmaVarianten": [flatten],
di68kap's avatar
di68kap committed
507
    "GrammatikPosition": [flatten],
508
509
    "wortart": [replace_or_reduce],
    "flexion": [],
510
511
512
    "deklination": [],
    "konjugation": [],
    "FLEX": [remove_whitespace, reduce_single_child],
513
    "genus": [replace_or_reduce],
di68kap's avatar
di68kap committed
514
515
    "nomen, verb, adverb, adjektiv, praeposition": [content_from_parser_name],
    "maskulinum, femininum, neutrum": [content_from_parser_name],
516
517
    "EtymologiePosition": [],
    "EtymologieVariante": [],
518
    "ArtikelKopf": [replace_by_single_child],
di68kap's avatar
di68kap committed
519
520
    "SchreibweisenPosition, StrukturPosition, VerwechselungsPosition, GebrauchsPosition":
        [],
Eckhart Arnold's avatar
Eckhart Arnold committed
521
    "Kategorien": [flatten],
522
523
524
    "Kategorie": [],
    "Varianten": [flatten],
    "Variante": [],
525
    "Beschreibung": [reduce_single_child],
526
527
    "Besonderheit": [reduce_single_child],
    "BedeutungsPosition": [flatten, remove_tokens("BEDEUTUNG")],
528
    "Bedeutung": [],
529
    "U1Bedeutung, U2Bedeutung, U3Bedeutung, U4Bedeutung, U5Bedeutung":
eckhart's avatar
eckhart committed
530
        [flatten],
di68kap's avatar
di68kap committed
531
    "Bedeutungskategorie": [flatten],
532
    "Beleg": [],
eckhart's avatar
eckhart committed
533
534
535
    "BelegText":
        [strip(lambda context: is_expendable(context) or has_content(context, '[".]')),
         reduce_single_child],
536
    "BelegStelle": [flatten],
537
    "Interpretamente": [],
538
539
540
541
542
    "LateinischeBedeutung": [remove_nodes("LAT"), flatten],
    "DeutscheBedeutung": [remove_nodes("DEU"), flatten],
    "LateinischerAusdruck": [flatten, reduce_single_child],
    "DeutscherAusdruck": [flatten, reduce_single_child],
    "LateinischesWort, DeutschesWort": [strip, collapse],
eckhart's avatar
eckhart committed
543
    "Belege": [flatten],
544
    "Beleg": [],
eckhart's avatar
eckhart committed
545
546
    "Zitat": [flatten],
    "Zusatz": [reduce_single_child, flatten],
di68kap's avatar
di68kap committed
547
548
    "ArtikelVerfasser": [],
    "Stellenverzeichnis": [],
eckhart's avatar
eckhart committed
549
    "Verweisliste": [flatten],
550
    "Stellenverweis": [flatten],
di68kap's avatar
di68kap committed
551
    "GebrauchsHinweis, PlurSingHinweis": [remove_whitespace, reduce_single_child],
di68kap's avatar
di68kap committed
552
    "Name": [collapse],
di68kap's avatar
di68kap committed
553
    "Stelle": [collapse],
eckhart's avatar
eckhart committed
554
    "Verweis": [],
di68kap's avatar
di68kap committed
555
556
    "VerweisKern": [flatten],
    "pfad, ziel": [reduce_single_child], # [apply_if(replace_content(lambda s: ''), has_parent("URL"))],
eckhart's avatar
eckhart committed
557
    "Anker": [reduce_single_child],
di68kap's avatar
di68kap committed
558
    "URL": [flatten, keep_nodes('protokoll', 'domäne', 'pfad', 'ziel'), replace_by_single_child],
559
560
    "NAMENS_ABKÜRZUNG": [],
    "NAME": [],
di68kap's avatar
di68kap committed
561
562
563
564
    "DEU_WORT": [reduce_single_child],
    "DEU_GROSS": [reduce_single_child],
    "DEU_KLEIN": [reduce_single_child],
    "LAT_WORT": [reduce_single_child],
565
566
    "GROSSSCHRIFT": [],
    "BUCHSTABENFOLGE": [],
567
    "EINZEILER, FREITEXT, MEHRZEILER": [strip, collapse],
568
569
570
571
572
573
574
575
576
577
578
579
580
    "ZEICHENFOLGE": [],
    "TR": [replace_or_reduce],
    "ABS": [replace_or_reduce],
    "LZ": [],
    "ZW": [],
    "ZWW": [],
    "LÜCKE": [],
    "LEERZEILE": [],
    "RZS": [],
    "ZEILENSPRUNG": [],
    "KOMMENTARZEILEN": [],
    "DATEI_ENDE": [],
    "NIEMALS": [],
581
    ":Token": [remove_whitespace, reduce_single_child],
582
    ":RE": reduce_single_child,
583
    "*": replace_by_single_child
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
}


def MLWTransform() -> TransformationDict:
    return partial(traverse, processing_table=MLW_AST_transformation_table.copy())

def get_transformer() -> TransformationFunc:
    global thread_local_MLW_transformer_singleton
    try:
        transformer = thread_local_MLW_transformer_singleton
    except NameError:
        thread_local_MLW_transformer_singleton = MLWTransform()
        transformer = thread_local_MLW_transformer_singleton
    return transformer


#######################################################################
#
# COMPILER SECTION - Can be edited. Changes will be preserved.
#
#######################################################################

di68kap's avatar
di68kap committed
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629

def lemma_verdichtung(lemma, variante):
    # finde den ersten Unterschied von links
    l = 0
    while l < min(len(lemma), len(variante)) and lemma[l] == variante[l]:
        l += 1

    # finde den ersten Unterschied von rechts
    r = 1
    while r <= min(len(lemma), len(variante)) and lemma[-r] == variante[-r]:
        r += 1
    r -= 1

    l -= 1              # beginne 1 Zeichen vor dem ersten Unterschied
    if l <= 1:  l = 0   # einzelne Buchstaben nicht abtrennen

    r -= 1              # beginne 1 Zeichen nach dem letzten Unterschied
    if r <= 1:  r = 0   # einzelne Buchstaben nicht abtrennen

    # gib Zeichenkette der Unterschide ab dem letzten gemeinsamen (von links) bzw.
    # ab dem ersten gemeinsamen (von rechts) Buchstaben mit Trennstrichen zurück
    return (('-' if l > 0 else '') + variante[l:(-r) or None] + ('-' if r > 0 else ''))


630
631
632
633
class MLWCompiler(Compiler):
    """Compiler for the abstract-syntax-tree of a MLW source file.
    """

di68kap's avatar
di68kap committed
634
635
636
637
638
639
640
641
    ZÄHLER = (
        ('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'),
        'ABCDEFGHI',
        '123456789',
        'abcdefghi',
        'αβγδεζηθι'
    )

642
643
644
    def __init__(self, grammar_name="MLW", grammar_source=""):
        super(MLWCompiler, self).__init__(grammar_name, grammar_source)
        assert re.match('\w+\Z', grammar_name)
di68kap's avatar
di68kap committed
645
        self.lemmawort = ""
646

di68kap's avatar
di68kap committed
647
648
649
650
651
    def on_VerweisKern(self, node):
        if node.children[0].parser.name == "FREITEXT":
            node.children[1].result = ""
        elif node.children[0].parser.name == "ziel":
            node.children[0].result = "v. ibi."
652
653
        return node

di68kap's avatar
di68kap committed
654
655
656
657
658
659
660
661
    def ergänze_Zähler(self, node, tiefe):
        i = 0
        for nd in node.children:
            if nd.parser.name == "Bedeutung":
                zähler = Node(MockParser("Zähler", ":RE"), self.ZÄHLER[tiefe][i])
                i += 1
                nd2 = nd.children[0]
                nd2.children = (zähler,) + nd2.children
662
663

    def on_BedeutungsPosition(self, node):
di68kap's avatar
di68kap committed
664
665
        self.ergänze_Zähler(node, 0)
        return self.fallback_compiler(node)
666

di68kap's avatar
di68kap committed
667
668
669
    def on_U1Bedeutung(self, node):
        self.ergänze_Zähler(node, 1)
        return self.fallback_compiler(node)
670

di68kap's avatar
di68kap committed
671
672
673
    def on_U2Bedeutung(self, node):
        self.ergänze_Zähler(node, 2)
        return self.fallback_compiler(node)
674

di68kap's avatar
di68kap committed
675
676
677
    def on_U3Bedeutung(self, node):
        self.ergänze_Zähler(node, 3)
        return self.fallback_compiler(node)
678

di68kap's avatar
di68kap committed
679
680
681
    def on_U4Bedeutung(self, node):
        self.ergänze_Zähler(node, 4)
        return self.fallback_compiler(node)
682

di68kap's avatar
di68kap committed
683
684
685
    def on_U5Bedeutung(self, node):
        self.ergänze_Zähler(node, 5)
        return self.fallback_compiler(node)
686

di68kap's avatar
di68kap committed
687
688
689
690
691
692
693
694
695
    def on_LemmaWort(self, node):
        assert not node.children
        self.lemmawort = node.result
        return node

    def on_LemmaVariante(self, node):
        assert not node.children
        node.xml_attr['verdichtung'] = lemma_verdichtung(self.lemmawort, node.result)
        return node
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715

def get_compiler(grammar_name="MLW", grammar_source="") -> MLWCompiler:
    global thread_local_MLW_compiler_singleton
    try:
        compiler = thread_local_MLW_compiler_singleton
        compiler.set_grammar_name(grammar_name, grammar_source)
    except NameError:
        thread_local_MLW_compiler_singleton = \
            MLWCompiler(grammar_name, grammar_source)
        compiler = thread_local_MLW_compiler_singleton
    return compiler


#######################################################################
#
# END OF DHPARSER-SECTIONS
#
#######################################################################


di68kap's avatar
di68kap committed
716
def compile_src(source, log_dir=''):
717
718
    """Compiles ``source`` and returns (result, errors, ast).
    """
di68kap's avatar
di68kap committed
719
    with logging(log_dir):
720
721
722
723
724
725
726
727
728
729
        compiler = get_compiler()
        cname = compiler.__class__.__name__
        log_file_name = os.path.basename(os.path.splitext(source)[0]) \
            if is_filename(source) < 0 else cname[:cname.find('.')] + '_out'    
        result = compile_source(source, get_preprocessor(), 
                                get_grammar(),
                                get_transformer(), compiler)
    return result


di68kap's avatar
di68kap committed
730
731
732
733
734
735
736
737
738
739
740
741
742
743
HTML_LEAD_IN = """<html>
<head>
<meta charset="UTF-8"/>
<link rel="stylesheet" href="MLW.css" />
</head>

<body>
"""

HTML_LEAD_OUT = """
</body>
</html>
"""

di68kap's avatar
di68kap committed
744
745
746
747
748
749
750
751
752
753
def write_as_html(file_name, tree, show=False):
    out_name = os.path.splitext(file_name)[0] + '.html'
    with open(out_name, 'w', encoding="utf-8") as f:
        f.write(HTML_LEAD_IN)
        f.write(tree.as_xml())
        f.write(HTML_LEAD_OUT)
    if show:
        webbrowser.open(out_name)


754
755
if __name__ == "__main__":
    if len(sys.argv) > 1:
di68kap's avatar
di68kap committed
756
757
758
759
        file_name, log_dir = sys.argv[1], ''
        if file_name in ['-d', '--debug'] and len(sys.argv) > 2:
            file_name, log_dir = sys.argv[2], 'LOGS'
        result, errors, ast = compile_src(file_name, log_dir)
760
        if errors:
di68kap's avatar
di68kap committed
761
762
            cwd = os.getcwd()
            rel_path = file_name[len(cwd):] if file_name.startswith(cwd) else file_name
763
            for error in errors:
di68kap's avatar
di68kap committed
764
                print(rel_path + ':' + str(error))
di68kap's avatar
di68kap committed
765
            print('\nLeider hat es ein paar Fehler gegeben :-(\n')
766
767
            sys.exit(1)
        else:
di68kap's avatar
di68kap committed
768
            write_as_html(file_name, result, show=True)
di68kap's avatar
di68kap committed
769
            print("Das Einlesen war erfolgreich :-)")
770
    else:
di68kap's avatar
di68kap committed
771
        print("Aufruf: MLWCompiler.py [--debug] FILENAME")