#!/usr/bin/env perl
#
# optlib2c - a tool translating ctags option file to C
#
# Copyright (C) 2016 Masatake YAMATO
# Copyright (C) 2016 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
use strict;
use warnings;
#use Data::Dumper;
#print Dumper(X);
sub show_help {
print< FILE.c
EOF
}
########################################################################
#
# PARSE
#
########################################################################
my $options =
[
[ qr/^--options=(.*)/, sub {
parse_optlib ($1, $_[0]);
return 1;
} ],
[ qr/^--__selector-(.*)=(.*)/, sub {
die "Don't use --__selector-= option before defining the language"
if (! defined $_[0]->{'langdef'});
$_[0]->{'selector'} = $2;
return 1;
} ],
#
# TODO: We should not assume the order of flags.
#
[ qr/^--langdef=([^\{]+)(((\{base=([^\{]+)\})(\{(dedicated|shared|bidirectional)\})?)?)(\{_autoFQTag\})?/, sub {
die "LANG is already defined as $_[0]->{'langdef'}: $1"
if (defined $_[0]->{'langdef'});
die "Don't use \"all\" as a language name. It is reserved word."
if ($1 eq "all");
$_[0]->{'langdef'} = $1;
$_[0]->{'base'} = $5 if defined $5;
$_[0]->{'direction'} = $7 if defined $7;
$_[0]->{'autoFQTag'} = (defined $8)? 1: 0;
die "Don't use a character as a language name other than alphanumeric, # and +: "
. $_[0]->{'langdef'} unless ($_[0]->{'langdef'} =~ /^[a-zA-Z0-9#+]+$/);
return 1;
} ],
[ qr/^--kinddef-(.*)=([^,]),([^,]+),([^\{]+)(\{_refonly\})?/, sub {
die "Don't use --kinddef-=+ option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding a kind is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
my $letter = $2;
my $name = $3;
my $desc = $4;
my $refonly = 0;
$refonly = 1 if defined $5;
die "'F' as a kind letter is reserved for file kind."
if ($letter eq 'F');
die "unacceptable character is used for kind letter: $letter"
unless ($letter =~ /^[a-zA-EG-Z]$/);
die "'file' as a kind name is reserved"
if ($name eq 'file');
die "The initial letter of kind name must be alphabetic character: $name"
unless (substr ($name, 0, 1) =~ /[a-zA-Z]/);
die "Letters used in kind name other than initial letter must be alphanumeric characters: $name"
unless (substr ($name, 1) =~ /^[a-zA-Z0-9]+$/);
push @{$_[0]->{'kinddefs'}}, { enabled => 1, letter => $letter, name => $name, desc => $desc,
refonly => $refonly, roles => [], seps => [] };
return 1;
} ],
[ qr/^--_extradef-(.*)=([^,]+),([^\{]+)/, sub {
die "Don't use --_extradef-=+ option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding an extra is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
my $name = $2;
my $desc = $3;
die "unacceptable character is used for extra name: $name"
unless ($name =~ /^[a-zA-Z0-9]+$/);
push @{$_[0]->{'extradefs'}}, { name => $name, desc => $desc };
return 1;
} ],
[ qr/^--_fielddef-(.*)=([^,]+),([^\{]+)/, sub {
die "Don't use --_fielddef-=+ option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding a field is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
my $name = $2;
my $desc = $3;
die "unacceptable character is used for field name: $name"
unless ($name =~ /^[a-zA-Z]+$/);
push @{$_[0]->{'fielddefs'}}, { name => $name, desc => $desc };
return 1;
} ],
[ qr/^--_roledef-([^.]*)\.(?:([a-zA-Z])|\{([a-zA-Z][a-zA-Z0-9]*)\})=([a-zA-Z0-9]+),([^\{]+)/, sub {
die "Don't use --_roledef-.=+ option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding a field is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
my $kind_found = 0;
for (@{$_[0]->{'kinddefs'}}) {
if ((defined $2 && $_->{'letter'} eq $2)
|| (defined $3 && $_->{'name'} eq $3)) {
my $role = { name => $4, desc => $5, owner => $_ };
push @{$_->{'roles'}}, $role;
$kind_found = 1;
last;
}
}
die "no such kind, \"$2\" where role \"$3\" is attached to" if (! $kind_found);
return 1;
} ],
[ qr/^--languages=-(.*)/, sub {
die "Don't use --languages=- option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Only language specified with --langdef can be disabled: $1"
unless ($_[0]->{'langdef'} eq $1);
$_[0]->{'disabled'} = 1;
return 1;
} ],
[ qr/^--language=(.*)/, sub {
die "--languages can be used only for disabling a language defined with --langdef: $1";
} ],
[ qr/^--map-([^=]*)=\+(.*)/, sub {
die "Don't use --map-=+ option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding a map is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
my $spec = $2;
if ($spec =~ /\((.*)\)/) {
push @{$_[0]->{'patterns'}}, $1;
} elsif ($spec =~ /\.(.*)/) {
push @{$_[0]->{'extensions'}}, $1;
} else {
die "Unexpected notation is used in the argument for --map-$1= option";
}
return 1;
} ],
[ qr/^--map-([^=]*)=[^+].*/, sub {
die "map manipulation other than the appending(--map-=+...) is not supported";
} ],
[ qr /^--alias-([^=]*)=\+(.*)/, sub {
die "Don't use --alias-=+ option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding an alias is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
push @{$_[0]->{'aliases'}}, $2;
return 1;
} ],
[ qr/^--alias-([^=]*)=[^+].*/, sub {
die "alias manipulation other than the appending(--alias-=+...) is not supported";
} ],
[ qr/^--regex-([^=]*)=(.*)/, sub {
die "Don't use --regex-= option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding a regex is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
return parse_regex ($2, $_[0], 0);
} ],
[ qr/^--mline-regex-([^=]*)=(.*)/, sub {
die "Don't use --mline-regex-= option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding a multiline regex is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
return parse_regex ($2, $_[0], 1);
} ],
[ qr/^--kinds-([^=]*)=-(.*)/, sub {
die "Don't use --kinds-= option before defining the language"
if (! defined $_[0]->{'langdef'});
parse_kinds ($2, $_[0]);
return 1;
} ],
[ qr/^--kinds-([^=]*)=(.*)/, sub {
die "--kinds-= can be used only for disabling a kind: $1";
} ],
[ qr/^--extras-([^=]*)=([-+])\{(.+)\}$/, sub {
die "Don't use --extras-= option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Enabling/disabling an extra is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
die "Specifing multiple extras in one --extras-... is not handled: {$3}"
if ( index ($3, '{') != -1 );
parse_extras ($2, $3, $_[0]);
return 1;
} ],
[ qr/^--extras-([^=]*)=\{/, sub {
die "--extras-= can be used only for enabling or disabling an extra: $1";
} ],
[ qr/^--extras-([^=]*)=(.)\{/, sub {
die "Unknown flag($2) is passed to --extras-= option";
} ],
[ qr/^--fields-([^=]*)=([-+])\{(.+)\}$/, sub {
die "Don't use --fields-= option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Enabling/disabling a field is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
die "Specifing multiple fields in one --fields-... is not handled: {$3}"
if ( index ($3, '{') != -1 );
parse_fields ($2, $3, $_[0]);
return 1;
} ],
[ qr/^--fields-([^=]*)=\{/, sub {
die "--fields-= can be used only for enabling or disabling a field: $1";
} ],
[ qr/^--fields-([^=]*)=(.)\{/, sub {
die "Unknown flag($2) is passed to --fields-= option";
} ],
[ qr/^--langmap=.*/, sub {
die "Use --map- option instead of --langmap";
} ],
[ qr/^--_tabledef-([^=]*)=(.*)/, sub {
die "Don't use --_tabledef-= option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding a table is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
$_[0]->{'tabledefs'}->{$2} = [];
push @{$_[0]->{'tablenames'}}, "$2";
return 1;
} ],
[ qr/^--_mtable-regex-([^=]*)=([^\/]+)(\/.*)/, sub {
die "Don't use --_mtable-regex-= option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Adding a multitable regex is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
return parse_regex ($3, $_[0], 1, $2);
} ],
[ qr/^--_mtable-extend-([^=]*)=(.*)\+(.*)/, sub {
die "Don't use --_mline-extend-= option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Extending a multitable regex is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
extend_table($_[0], $2, $3);
return 1;
} ],
[ qr/^--_(prelude|sequel)-([^=]*)=(\{\{)$/, sub {
die "Don't use --_mtable-regex-= option before defining the language"
if (! defined $_[0]->{'langdef'});
my $hook = $_[0]->{$1};
my $slot = @$hook;
push @$hook, $3;
return sub {
$hook->[$slot] = $hook->[$slot] . $_[0];
}
}],
[ qr/^--_(prelude|sequel)-([^=]*)=(\{\{.*\}\})$/, sub {
die "Don't use --_mtable-regex-= option before defining the language"
if (! defined $_[0]->{'langdef'});
my $hook = $_[0]->{$1};
my $slot = @$hook;
push @$hook, $3;
return 1;
}],
[ qr/^--_scopesep-([^=]*)=([^,]?)\/([^:]+):(.+)/, sub {
die "Don't use --_scopesep-= option before defining the language"
if (! defined $_[0]->{'langdef'});
die "Specifying a scope separator is allowed only to the language specified with --langdef: $1"
unless ($_[0]->{'langdef'} eq $1);
scopesep($_[0], $2, $3, $4);
return 1;
} ],
[ qr/^-.*/, sub {
die "Unhandled option: \"$&\"";
} ],
[ qr/.*/, sub {
die "Unhandled argument: \"$&\"";
} ],
];
sub parse_line {
my ($line, $opts) = @_;
my $r = 0;
for (@{$options}) {
my ($pat, $action) = @{$_};
if ($line =~ $pat) {
$r = $action -> ($opts);
last;
}
}
$r;
}
sub gather_chars {
my $input = shift;
my $output = "";
my $escape = 0;
my $c;
# See scanSeparators() of lregex.c.
while (defined ($c = shift @{$input})) {
if ($escape) {
if ($c eq '/') {
$output = $output . $c;
} elsif ($c eq 't') {
$output = $output . '\\' . 't';
} elsif ($c eq 'n') {
$output = $output . '\\' . 'n';
} elsif ($c eq '\\') {
$output = $output . '\\\\' . '\\\\';
} else {
$output = $output . '\\\\' . $c;
}
$escape = 0;
} elsif ($c eq '"') {
$output = $output . '\\' . $c;
} elsif ($c eq '\\') {
$escape = 1;
} elsif ($c eq '/') {
last;
} else {
$output = $output . $c;
}
}
return ($output, (defined $c)? $c: "");
}
sub parse_regex {
my ($regspec, $opts, $mline, $table) = @_;
my @chars = split //, $regspec;
# TODO:
# ctags allows using a char other than '/'
#
if (! ($chars[0] eq '/')) {
if (!$mline) {
die "--regex-= option is not started from /: $regspec";
} else {
die "--mline-regex-= option is not started from /: $regspec";
}
}
shift @chars;
my $last_char;
my $regex;
($regex, $last_char) = gather_chars (\@chars);
if (! ($last_char eq '/')) {
if (!$mline) {
die "The pattern in --regex-= option is not ended with /: $regspec";
} else {
die "The pattern in --mline-regex-= option is not ended with /: $regspec";
}
}
my $name;
($name, $last_char) = gather_chars (\@chars);
if (! ($last_char eq '/')) {
die "Wrong kind/flags syntax: $regspec";
}
my $tmp;
($tmp, $last_char) = gather_chars (\@chars);
my $kind = "";
my $flags;
if ( (! @chars) && (! ($last_char eq '/'))) {
$flags = $tmp;
} else {
$kind = $tmp;
}
if ($last_char eq '/') {
($flags, $last_char) = gather_chars (\@chars);
}
my $optscript = '';
if ($flags =~ /(.*)\{\{$/) {
$flags = $1;
$optscript = "{{\n";
}
my $entry;
if (defined $table) {
if (! (substr ($regex, 0, 1) eq '^')) {
$regex = '^' . $regex;
}
$entry = { 'regex' => $regex,
'name' => $name,
'kind' => $kind,
'flags' => $flags,
'mline' => $mline,
'optscript' => $optscript,
};
push @{$opts->{'tabledefs'}->{"$table"}}, $entry;
} else {
$entry = { 'regex' => $regex,
'name' => $name,
'kind' => $kind,
'flags' => $flags,
'mline' => $mline,
'optscript' => $optscript,
};
push @{$opts->{'regexs'}}, $entry;
}
if ($flags =~ '{scope=' || $optscript) {
$opts->{'useCork'} = 1;
}
return $optscript
? sub {
$entry->{'optscript'} = $entry->{'optscript'} . $_[0];
}
: 1;
}
sub extend_table {
my ($opts, $dist, $src) = @_;
for (@{$opts->{'tabledefs'}->{$src}}) {
push @{$opts->{'tabledefs'}->{$dist}}, $_;
}
}
sub parse_kinds {
my ($kinds, $opts) = @_;
for my $letter (split //, $kinds) {
for (@{$opts->{'kinddefs'}}) {
if ($_->{'letter'} eq $letter) {
$_->{'enabled'} = 0;
}
}
}
}
sub parse_optlib {
my ($optlib, $opts) = @_;
open(my $optlibfh, "<", $optlib)
or die "cannot open the optlib file: \"$optlib\"";
my $receiver = 0;
while (<$optlibfh>) {
chomp;
if (/^\}\}$/ && $receiver && ($receiver != 1)) {
$receiver->('}}');
$receiver = 1;
}
elsif ($receiver && $receiver != 1) {
my $str = escape_as_cstr ($_);
$receiver->($str);
$receiver->("\n");
} elsif ( /^[[:blank:]]*#.*/ ) {
next;
} else {
s/^\s*//;
next if ( /^\s*$/ );
$receiver = parse_line ($_, $opts);
if (! $receiver) {
return undef;
}
}
}
return $opts;
}
sub parse_extras {
my ($flag, $extra, $opts) = @_;
$flag = ( $flag eq '+' )?1: 0;
# TODO: Hash table should be used for manage 'extradefs'.
for (@{$opts->{'extradefs'}}) {
if ($_->{'name'} eq $extra)
{
$_->{'enabled'} = $flag;
}
}
}
sub parse_fields {
my ($flag, $field, $opts) = @_;
$flag = ( $flag eq '+' )?1: 0;
# TODO: Hash table should be used for manage 'fielddefs'.
for (@{$opts->{'fielddefs'}}) {
if ($_->{'name'} eq $field)
{
$_->{'enabled'} = $flag;
}
}
}
sub scopesep {
my ($opts, $parent_kletter, $kletter, $sep) = @_;
if ($kletter eq '*') {
if ($parent_kletter eq '*') {
$opts->{'defaultScopeSeparator'} = $sep;
} elsif (!$parent_kletter) {
$opts->{'defaultRootScopeSeparator'} = $sep;
} else {
die "Unhandled kind letter during parsing --_scopsesep option: $parent_kletter";
}
} elsif ($kletter =~ /[a-zA-Z]/) {
my $kind;
for (@{$opts->{'kinddefs'}}) {
if ($_->{'letter'} eq $kletter) {
$kind = $_;
last;
}
}
die "Unknown kind letter in --_scopsesep option: $kletter"
unless defined $kind;
if ($parent_kletter eq '*') {
push @{$kind->{'seps'}}, { parentKindIndex => 'KIND_WILDCARD_INDEX',
sep => $sep };
} elsif (!$parent_kletter) {
push @{$kind->{'seps'}}, { parentKindIndex => 'KIND_GHOST_INDEX',
sep => $sep };
} elsif ($parent_kletter =~ /[a-zA-Z]/) {
my $parent_kind;
for (@{$opts->{'kinddefs'}}) {
if ($_->{'letter'} == $parent_kletter) {
$parent_kind = $_;
last;
}
}
die "Unknown kind letter in --_scopsesep option: $parent_kletter"
unless defined $parent_kind;
push @{$kind->{'seps'}}, { parentKindIndex => 'K_' . (uc $parent_kind->{'name'}),
sep => $sep };
}
} else {
die "Unhandled kind letter during parsing --_scopsesep option: $kletter";
}
$opts->{'hasSepSpeicifer'} = 1;
}
########################################################################
#
# EMIT
#
########################################################################
sub emit_header {
my ($optlib, $opts) = @_;
print <{'base'}) {
print <{'selector'}) {
print <{'tablenames'} ? "": " CTAGS_ATTR_UNUSED";
print <{'Clangdef'}Parser (const langType language$may_unused)
{
EOF
for (@{$opts->{'prelude'}}) {
my $prelude = "";
for my $frag (split /\n/, $_) {
$prelude = $prelude . "\n\t\t\"" . $frag . ($frag =~ /.*\}\}$/
? '"'
: '\n"');
}
print <{'sequel'}}) {
my $sequel = "";
for my $frag (split /\n/, $_) {
$sequel = $sequel . "\n\t\t\"" . $frag . ($frag =~ /.*\}\}$/
? '"'
: '\n"');
}
print <{'tablenames'}) {
print "\n";
for (@{$opts->{'tablenames'}}) {
print <{'tablenames'}}) {
for (@{$opts->{'tabledefs'}->{"$table"}}) {
my $optscript = "";
if ($_-> {'optscript'}) {
for my $frag (split /\n/, $_-> {'optscript'}) {
$optscript = $optscript . "\n\t\t\"" . $frag . ($frag =~ /.*\}\}$/
? '"'
: '\n"');
}
}
print <{'regex'}",
"$_->{'name'}", "$_->{'kind'}", "$_->{'flags'}"$optscript, NULL);
EOF
}
}
}
print <{$key}}) {
print <{'kinddefs'}}) {
next unless @{$_->{'roles'}};
my $Kind = capitalize($_->{'name'});
print <{'Clangdef'}${Kind}RoleTable [] = {
EOF
for (@{$_->{'roles'}}) {
my $desc = escape_as_cstr $_->{'desc'};
print <{'name'}", "$desc" },
EOF
}
print <{'kinddefs'}});
print <{'kinddefs'}}) {
my $e = uc($_->{'name'});
print <{'Clangdef'}Kind;
EOF
}
sub emit_scopeseps {
my $opts = shift;
return if (! @{$opts->{'kinddefs'}});
for (@{$opts->{'kinddefs'}}) {
my $seps = $_->{'seps'};
if (@{$seps}) {
my $Kind = capitalize ($_->{'name'});
print <{'Clangdef'}${Kind}Separators [] = {
EOF
for (@{$seps}) {
print <{'parentKindIndex'}, "$_->{'sep'}" },
EOF
}
print <{'kinddefs'}});
print <{'Clangdef'}KindTable [] = {
EOF
for (@{$opts->{'kinddefs'}}) {
my $enabled = $_->{"enabled"}? "true": "false";
print <{'desc'};
print <{'letter'}\', "$_->{'name'}", "$desc",
EOF
if ($_->{'refonly'}) {
print <{'name'});
if (@{$_->{'roles'}}) {
print <{'Clangdef'}${Kind}RoleTable),
EOF
}
if (@{$_->{'seps'}}) {
print <{'Clangdef'}${Kind}Separators),
EOF
}
print <{'regexs'}});
print <{'Clangdef'}TagRegexTable [] = {
EOF
for (@{$opts->{'regexs'}}) {
my $flags;
if ($_-> {'flags'}) {
$flags = '"' . $_-> {'flags'} . '"';
if ($_-> {'optscript'}) {
for my $frag (split /\n/, $_-> {'optscript'}) {
$flags = $flags . "\n\t\t\"" . $frag . ($frag =~ /.*\}\}$/
? '"'
: '\n"');
}
}
} else {
if ($_-> {'optscript'}) {
$flags = '""';
for my $frag (split /\n/, $_-> {'optscript'}) {
$flags = $flags . "\n\t\t\"" . $frag . ($frag =~ /.*\}\}$/
? '"'
: '\n"');
}
} else {
$flags = 'NULL';
}
}
my $mline = $_-> {'mline'}? "true": "false";
print <{'regex'}", "$_->{'name'}",
"$_->{'kind'}", $flags, NULL, $mline},
EOF
}
print <{'base'});
my $direction = "SUBPARSER_BASE_RUNS_SUB";
if (defined $opts->{'direction'})
{
if ($opts->{'direction'} eq 'shared')
{
$direction = "SUBPARSER_BASE_RUNS_SUB";
} elsif ($opts->{'direction'} eq 'dedicated')
{
$direction = "SUBPARSER_SUB_RUNS_BASE";
} elsif ($opts->{'direction'} eq 'bidirectional')
{
$direction = "SUBPARSER_BI_DIRECTION";
}
}
print <{'Clangdef'}Subparser = {
.direction = $direction,
};
static parserDependency $opts->{'Clangdef'}Dependencies [] = {
[0] = { DEPTYPE_SUBPARSER, "$opts->{'base'}", &$opts->{'Clangdef'}Subparser },
};
EOF
}
sub emit_xtags {
my $opts = shift;
return if (! @{$opts->{'extradefs'}});
print <{'Clangdef'}XtagTable [] = {
EOF
for (@{$opts->{'extradefs'}}) {
my $enabled = $_->{"enabled"}? "true": "false";
my $desc = escape_as_cstr $_->{'desc'};
print <{'fielddefs'}});
print <{'Clangdef'}FieldTable [] = {
EOF
for (@{$opts->{'fielddefs'}}) {
my $enabled = $_->{"enabled"}? "true": "false";
my $desc = escape_as_cstr $_->{'desc'};
print <{'selector'}) {
print <{'selector'}, NULL };
EOF
}
}
sub emit_fields_initialization {
my $opts = shift;
my $enabled = $opts->{"disabled"} ? "false": "true";
my $method;
my $sep;
$method = "METHOD_NOT_CRAFTED";
if (@{$opts->{"regexs"}} || $opts->{'tablenames'}) {
$method = "${method}|METHOD_REGEX";
}
print <enabled = ${enabled};
def->extensions = extensions;
def->patterns = patterns;
def->aliases = aliases;
EOF
if (defined $opts->{'selector'}) {
print <selectLanguage= selectors;
EOF
}
print <method = ${method};
EOF
if ($opts->{'useCork'}) {
print <useCork = CORK_QUEUE;
EOF
}
if (@{$opts->{'kinddefs'}}) {
print <kindTable = $opts->{'Clangdef'}KindTable;
def->kindCount = ARRAY_SIZE($opts->{'Clangdef'}KindTable);
EOF
}
if (@{$opts->{'fielddefs'}}) {
print <fieldTable = $opts->{'Clangdef'}FieldTable;
def->fieldCount = ARRAY_SIZE($opts->{'Clangdef'}FieldTable);
EOF
}
if (@{$opts->{'extradefs'}}) {
print <xtagTable = $opts->{'Clangdef'}XtagTable;
def->xtagCount = ARRAY_SIZE($opts->{'Clangdef'}XtagTable);
EOF
}
if (@{$opts->{'regexs'}}) {
print <tagRegexTable = $opts->{'Clangdef'}TagRegexTable;
def->tagRegexCount = ARRAY_SIZE($opts->{'Clangdef'}TagRegexTable);
EOF
}
if (defined $opts->{'base'}) {
print <dependencies = $opts->{'Clangdef'}Dependencies;
def->dependencyCount = ARRAY_SIZE($opts->{'Clangdef'}Dependencies);
EOF
}
if ($opts->{'autoFQTag'}) {
print <requestAutomaticFQTag = true;
EOF
}
if ($opts->{'defaultScopeSeparator'}) {
$sep = "$opts->{'defaultScopeSeparator'}";
$sep = escape_as_cstr "$sep";
print <defaultScopeSeparator = "$sep";
EOF
}
if ($opts->{'defaultRootScopeSeparator'}) {
$sep = $opts->{'defaultRootScopeSeparator'};
$sep = escape_as_cstr "$sep";
print <defaultRootScopeSeparator = "$sep";
EOF
}
print <initialize = initialize$opts->{'Clangdef'}Parser;
EOF
}
sub emit {
my ($optlib, $opts) = @_;
emit_header ($optlib, $opts);
if ($opts->{'hasSepSpeicifer'}) {
emit_kinddef_enums $opts;
};
emit_initializer $opts;
print <{'Clangdef'}Parser (void)
{
EOF
emit_extensions $opts;
emit_aliases $opts;
emit_patterns $opts;
emit_roledefs $opts;
emit_scopeseps $opts;
emit_kinddefs $opts;
emit_fields $opts;
emit_xtags $opts;
emit_regexs $opts;
emit_dependencies $opts;
emit_selector $opts;
print "\n";
print <{'langdef'}");
EOF
emit_fields_initialization $opts;
print < {'langdef'};
$opts -> {'Clangdef'} = capitalize ($langdef);
}
########################################################################
#
# MAIN
#
########################################################################
sub main {
my $optlib;
my %opts = (langdef => undef,
Clangdef => undef,
disabled => 0,
patterns => [],
extensions => [],
aliases => [],
regexs => [# { regex => "", name => "", kind => "", flags => "", mline => 1|0, optscript => "" },
],
kinddefs => [# { letter => '', name => "", desc => "",
# seps => [ {parentKindIndex => "", sep => "" } ]
# },
],
extradefs => [ # { name => "", desc => "", enabled => 1|0 },
],
fielddefs => [ # { name => "", desc => "", enabled => 1|0 },
],
base => undef,
tableNames => [ # ""
],
tabledefs => { # "" => [{ regex => "", name => "", kind => "", flags => "" }...],
},
useCork => 0,
defaultScopeSeparator => undef,
defaultRootScopeSeparator => undef,
hasSepSpeicifer => 0,
prelude => [ # ""
],
sequel => [ # ""
],
selector => undef,
);
for (@_) {
if ( ($_ eq '-h') || ($_ eq '--help') ) {
show_help;
exit 0;
} elsif ( /^-.*/ ) {
die "unrecongnized option: $_";
} else {
if ($optlib) {
die "Too man input files: @_";
}
$optlib=$_;
}
}
if (! $optlib) {
die "No optlib file name is given";
}
if (! parse_optlib ($optlib, \%opts)) {
exit 1;
}
rearrange (\%opts);
if (! emit ($optlib, \%opts) ) {
exit 1;
}
0;
}
main @ARGV;
# optlib2c ends here.