#!/usr/bin/perl # To debug: # perl -s make_tokenizer.pl -RD_HINT -RD_TRACE > make_tokenizer.out 2>&1 use strict; use warnings; use Parse::RecDescent (); my $grammar = <<'__EOI__'; { my %keywords = ( map { $_ => 'keyword' } qw( array call constant debug else elseif endfunction endglobals endif endloop exitwhen extends function globals if local loop native nothing return returns set takes then type ), and => 'operator', or => 'operator', not => 'operator', null => 'null', false => 'bool', true => 'bool', ); } tokenize : token(s?) { $item[2] } token : ident { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } # | keyword { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | ws { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | comment { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | list_sep { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | paren { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | bracket { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | operator { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | assign { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | string { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | real { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | decimal { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | hex { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | octal { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | packed { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } # | bool { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } # | null { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } | unknown { [ $item[1], $itempos[1]{offset}{from}, $itempos[1]{offset}{to} ] } ident : /[a-zA-Z](?:[a-zA-Z0-9_]*[a-zA-Z0-9])?/ { ($keywords{$item[1]} || 'ident') } ws : m'\s+' { $item[0] } comment : m'//[^\n]*' { $item[0] } list_sep : ',' { $item[0] } paren : m'[()]' { $item[0] } bracket : m'[\[\]]' { $item[0] } operator : m'[-+*/]|[=!]=|>=?|<=?' { $item[0] } assign : '=' { $item[0] } #string : /"(?:[^\\"\n]|\\[^\n])*"/ { $item[0] } string : /"(?:[^\\"\n]|\\[^\n])*(?:"|(?=\n))/ { $item[0] } real : /[0-9]+\.[0-9]*/ { $item[0] } | /\.[0-9]+/ { $item[0] } decimal : /[1-9][0-9]*/ { $item[0] } #hex : /\$[0-9a-fA-F]+/ { $item[0] } # | /0[xX][0-9a-fA-F]+/ { $item[0] } hex : /\$[0-9a-fA-F]*/ { $item[0] } | /0[xX][0-9a-fA-F]*/ { $item[0] } octal : /0[0-7]*/ { $item[0] } #packed : /'[^'\n]{4}'/ { $item[0] } packed : /'[^'\n]{0,4}'?/ { $item[0] } unknown : /./ { $item[0] } __EOI__ rename('JassTokenizer.pm', 'JassTokenizer.pm.bak'); Parse::RecDescent->Precompile($grammar, 'JassTokenizer') or die("Bad grammar.\n");