source: src/genparser.pl @ cd76f9

Revision cd76f9, 3.7 KB checked in by Tomash Brechko <tomash.brechko@…>, 4 years ago (diff)

Remove 'by' from copyright statement.

  • Property mode set to 100755
Line 
1#! /usr/bin/perl
2#
3# Copyright (C) 2007 Tomash Brechko.  All rights reserved.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the same terms as Perl itself, either Perl version 5.8.8
7# or, at your option, any later version of Perl 5 you may have
8# available.
9#
10use warnings;
11use strict;
12
13use FindBin;
14
15@ARGV == 3
16  or die "Usage: $FindBin::Script KEYWORD_FILE FILE_C FILE_H\n";
17
18my ($keyword_file, $file_c, $file_h) = @ARGV;
19
20
21my %C;
22my @keywords;
23
24open(my $kw, '<', $keyword_file)
25  or die "open(< $keyword_file): $!";
26
27my $section = 0;
28while (my $line = <$kw>) {
29    chomp $line;
30
31    if ($line =~ /^\s*(?:#.*)?$/) {
32        next;
33    } elsif ($line =~ /^\s*%%\s*$/) {
34        ++$section;
35        next;
36    }
37
38    if ($section == 0 and $line =~ /^\s*(\S+)\s*=\s*(\S+)\s*$/) {
39        $C{$1} = $2;
40    } elsif ($section == 1) {
41        push @keywords, $line;
42    } else {
43        die "Can't parse line: $line";
44    }
45}
46
47close($kw);
48
49
50sub dispatch_keywords {
51    my ($words) = @_;
52
53    return $words if @$words <= 1;
54
55    my $len = 0;
56    my $common = 1;
57    while ($common) {
58        ++$len;
59        my $prefix = substr($$words[0], 0, $len);
60        $common = ! grep(!/^$prefix/, @$words);
61    }
62    --$len;
63
64    my $prefix = substr($$words[0], 0, $len);
65
66    my %subtree;
67    foreach my $word (@$words) {
68        my $key = substr($word, $len, 1);
69        my $val = substr($word, $len + 1);
70        push @{$subtree{$key}}, $val;
71    }
72
73    foreach my $val (values %subtree) {
74        $val = dispatch_keywords($val);
75    }
76
77    return [$prefix, \%subtree];
78}
79
80
81my $tree = dispatch_keywords(\@keywords);
82
83
84my @external_enum = qw(NO_MATCH);
85
86sub create_switch {
87    my ($depth, $prefix, $common, $hash) = @_;
88
89    my $I = ' ' x ($depth * 4);
90    my @keys = sort keys %$hash;
91    (my $common_ident = $common) =~ s/[^A-Z_]//g;
92    my $phase = $prefix . $common_ident;
93    my $res = '';
94
95    if ($common) {
96        if ($C{loose_match}) {
97            $res .= <<"EOF";
98$I  *pos += @{[ length $common ]};
99
100EOF
101        } else {
102            $res .= <<"EOF";
103$I  match_pos = "$common";
104
105$I  do
106$I    {
107$I      if (**pos != *match_pos)
108$I        return NO_MATCH;
109
110$I      ++*pos;
111$I      ++match_pos;
112$I    }
113$I  while (*match_pos != '\\0');
114
115EOF
116        }
117    }
118    if ($common or $depth) {
119        if (! @keys) {
120            push @external_enum, $phase;
121            $res .= <<"EOF";
122$I  return $phase;
123
124EOF
125            return $res;
126        }
127    }
128
129    $res .= <<"EOF";
130$I  switch (*(*pos)++)
131$I    {
132EOF
133
134    foreach my $key (@keys) {
135        my $subphase = $phase . $key;
136        $res .= <<"EOF";
137$I    case '$key':
138EOF
139        $res .= create_switch($depth + 1, $subphase, @{$$hash{$key}});
140    }
141
142    $res .= <<"EOF";
143$I    default:
144$I      return NO_MATCH;
145$I    }
146EOF
147
148    return $res;
149}
150
151
152my $switch = create_switch(0, 'MATCH_', @$tree);
153
154
155my $gen_comment = <<"EOF";
156/*
157  This file was generated with $FindBin::Script from
158  $keyword_file.
159
160  Instead of editing this file edit the keyword file and regenerate.
161*/
162EOF
163
164
165open(my $fc, '>', $file_c)
166  or die "open(> $file_c): $!";
167
168my $i = 0;
169print $fc <<"EOF";
170$gen_comment
171#include "$file_h"
172
173
174enum $C{parser_func}_e
175$C{parser_func}(char **pos)
176{
177EOF
178
179unless ($C{loose_match}) {
180    print $fc <<"EOF";
181  char *match_pos;
182
183EOF
184}
185
186print $fc <<"EOF";
187$switch
188  /* Never reach here.  */
189}
190EOF
191
192close($fc)
193  or die "close($file_c): $!";
194
195
196my $guard = uc $file_h;
197$guard =~ s/[^[:alnum:]_]/_/g;
198
199open(my $fh, '>', $file_h)
200  or die "open(> $file_h): $!";
201
202print $fh <<"EOF";
203$gen_comment
204#ifndef $guard
205#define $guard 1
206
207
208enum $C{parser_func}_e {
209  @{[ join ",\n  ", @external_enum ]}
210};
211
212
213extern
214enum $C{parser_func}_e
215$C{parser_func}(char **pos);
216
217
218#endif /* ! $guard */
219EOF
220
221close($fh)
222  or die "close($file_h): $!";
Note: See TracBrowser for help on using the repository browser.