summaryrefslogtreecommitdiff
path: root/scripts/fix-flex
blob: 614331f5c6fd50bdd6f2fff6d0041b4ea0bd06fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/perl
#
# Format output generated by flex 2.5.31
#
# Usage:
#  flex -o$output $input
#  perl fix-flex $output > $tmp
#  mv $tmp $output
#
# (C) Copyright 2004-2014 Dave Beckett http://www.dajobe.org/
# (C) Copyright 2004 University of Bristol
#

my $line_offset = 1; # #line directives always refer to the NEXT line

print <<'EOT';
#ifdef HAVE_CONFIG_H
#include <raptor_config.h>
#endif

EOT
$line_offset += 4; # added 4 lines above to output

my $debug = 0;

# Lexer symbol prefix such as 'turtle_lexer_'
my $prefix = undef;
# Current function or undef if out of function
my $cur_function = undef;
# State for current function for rules to use.
my(%fn_state);

while(<>) {
  # find lexer prefix
  if(!defined($prefix) && /^void\s*(.+?)restart\s*\(.*;$/) {
    $prefix = $1;
    warn "$.: Lexer prefix $prefix\n"
	if $debug > 0;
  }

  # Remove generated yy_fatal_error declaration and definition to avoid warnings about unused/non-defined static function
  # declaration
  if(/^static void yy_fatal_error\s*\(.*\)\s*\;\s*$/) {
    $line_offset--; # skipped 1 line
    next;
  }
  # definition
  if(/^static void yy_fatal_error\s*\(.*\)\s*[^\;]\s*$/) {
    do {
      $_=<>;
      $line_offset--; # skipped 1 line
    } while(!/^}/);
    $line_offset--; # skipped 1 line
    next;
  }

  # Replace calls to yy_fatal_error("msg", yyscanner) to YY_FATAL_ERROR("msg") macro
  s/(^\s*)yy_fatal_error\s*\(\s*(\".*\")\s*,\s*yyscanner\s*\)/$1YY_FATAL_ERROR($2)/;

  # flex has %option nounistd however it does not work in 2.5.31
  # It is safe to add yet another wrapper. 
  if(m%^(\#include \<unistd.h\>)$%) {
    $_=<<"EOT";
#ifndef YY_NO_UNISTD_H
$1
#endif
EOT
    $line_offset += 2; # added 2 lines to output
  }

  # Fix .[ch] line references because we have added lines to it
  my $line = $. + $line_offset;
  s/^#line \d+ (\".*\.[ch]\")/#line $line $1/;

  # Fix signed / unsigned comparison gcc 4.x warning:
  #   int n : in the macro YY_INPUT definition
  #   (size_t)num_to_read : which is silly since num_to_read is an int!
  s/yyg->yy_n_chars, \(size_t\) num_to_read \)/yyg->yy_n_chars, num_to_read \)/;


  # Match prefixed functions and a couple of static ones starting yy_
  if(!defined($cur_function) && /^.*?((?:${prefix}|yy_)\w+)\s+\((.*)$/) {
    my($f,$rest)=($1,$2);
    if($rest !~ /;$/) {
      $cur_function=$1;
      warn "$.: Now in $cur_function: $_\n"
	  if $debug > 1;
      %fn_state=();
    }
  } elsif(defined($cur_function) && /^\}/) {
    warn "$.: End of $cur_function\n"
	if $debug > 1;
    $cur_function = undef;
    %fn_state=();
  }

  # Fix declaration of signed 'i' operating over range of yy_size_t
  if($cur_function eq $prefix."_scan_bytes") {
    s/int i;/yy_size_t i;/;
  }

  # Add $prefix_cleanup() call at the end of $prefix_lex_destroy()
  # find the start of lex_destroy function definition and capture prefix
  # look for lexer_free(yyscanner, yyscanner) statement within the function and place the cleanup call before it
  if($cur_function eq $prefix."lex_destroy") {
    if(/(^\s*)(${prefix}free\s*\(\s*yyscanner\s*,\s*yyscanner\s*\)\s*\;)\s*$/) {
      $_=<<"EOT";
$1/* clean up leaks if any before freeing yyscanner */
$1${prefix}cleanup(yyscanner);
$1$2
EOT
      $line_offset += 2; # added 2 lines to output
    }
  }

  if($cur_function eq $prefix."_switch_to_buffer" ||
     $cur_function eq $prefix."restart" ||
     $cur_function eq $prefix."push_buffer_state") {
    if(!exists($fn_state{'seen_ensure'}) &&
       m%^\s*${prefix}ensure_buffer_stack\s*\(%) {
      $fn_state{'seen_ensure'} = 1;
    } elsif(exists($fn_state{'seen_ensure'})) {
      # In condition with whitespace
      s%(\s+)YY_CURRENT_BUFFER(\s+)%${1}YY_CURRENT_BUFFER_LVALUE${2}%;
      # In parameter or condition
      s%([,\(])YY_CURRENT_BUFFER([,\)])%${1}YY_CURRENT_BUFFER_LVALUE${2}%;
    }
  }

  if($cur_function eq 'yy_get_next_buffer') {
    if(!exists($fn_state{'seen_yyinput'}) &&
       m%^\s*YY_INPUT\(%) {
      $fn_state{'seen_yyinput'} = 1;
    } elsif(exists($fn_state{'seen_yyinput'})) {
      # Remove dead code after YY_INPUT - which is a return NULL
      s%^\s*YY_CURRENT_BUFFER_LVALUE->yy_n_chars\s*=\s*yyg->yy_n_chars;%%;
    }
  }

  if($cur_function eq $prefix.'pop_buffer_state') {
    # Change last if use of YY_CURRENT_BUFFER macro to unconditional value
    s%^(\s*if \(\s*)YY_CURRENT_BUFFER(\s*\)\s*\{.*)$%${1}YY_CURRENT_BUFFER_LVALUE${2}%;
  }

  print;
}