#!/usr/bin/env perl # # This is Ano script -> C struct compiler. # # Compiler is designed to parse asm-like Ano-script syntax. Compiler lacks # advanced error and syntax checking and such, but it works. # # Copyright (c) 2016-2024, Jani Salonen # All rights reserved. # use 5.10.0; use utf8; use warnings; # This is version tag for output file and must match with the engine's PACKAGE_VERSION # my $DSL_COMPILER_VER = "0.2.9"; # Global storage for various things # my @dsl_cmd_r = (); my %var_store = (); my %var_usage = (); my %var_const = (); my @var_alias = (); my %var_incmp = (); my %var_intry = (); my %var_invar = (); my %var_cases = (); my %var_tries = (); my %var_throw = (); my @var_jumps = (); my @var_hooks = (); my @var_tails = (); my $var_label = 1; my $var_tests = 1; my $var_trigs = 1; my $var_loops = 0; my $var_funcs = 0; my $var_where = ""; my %var_these = (); my $var_i = 0; my $var_p = 1; my $var_r = ""; my $cnt_i = 1; # my $on_struct = 0; my $str_where = 0; my @str_items = (); my %str_these = (); my %str_names = (); my %str_types = (); my %str_inits = (); my %str_store = (); # my %fnc_proto = (); # my %alt_unveil = (); my %alt_remote = (); my %alt_zapper = ( 'deny' => 'IS_NO', 'allow' => 'IS_YES' ); my %alt_flags = ( '@ANO_FLAGS_DEFAULT_CHARSET' => '', '@ANO_FLAGS_USE_PROTOS' => '', '@ANO_FLAGS_VAR_NAME_SUBS' => '', '@ANO_FLAGS_VAR_WARN_UNUSED' => '' ); my %alt_store = ( '@ANO_SCRIPT_NAME' => '', '@ANO_SCRIPT_VERSION' => '', '@ANO_SCRIPT_DESCRIPTION' => '', '@ANO_SCRIPT_COPYRIGHT' => '', '@TAG_ATTR_COMPANY' => '', '@TAG_ATTR_CONTACT' => '', '@TAG_ATTR_CREATED' => '', '@TAG_ATTR_DEPARTMENT' => '', '@TAG_ATTR_DESCRIPTION' => '', '@TAG_ATTR_HOMEDIRECTORY' => '', '@TAG_ATTR_HOMEPAGE' => '', '@TAG_ATTR_MAIL' => '', '@TAG_ATTR_NOTES' => '', '@TAG_ATTR_OPTIONS' => '', '@TAG_ATTR_ORGANIZATION' => '', '@TAG_ATTR_ORIGINALNAME' => '', '@TAG_ATTR_OWNER' => '', '@TAG_ATTR_REMOTECONTROLPORT' => '', '@TAG_ATTR_REMOTECONTROLPROTO' => '', '@TAG_ATTR_SCRIPTPATH' => '', '@TAG_ATTR_SEEALSO' => '', '@TAG_ATTR_SERIALNUMBER' => '' ); # my %fnc_par_n = &fnc_par_names(); my @pre_inc_n = &pre_inc_macro(); # my %arg_types = (); my %arg_store = ( 'ano_sources' => [ ] ); # Parse command line... # my @file_inc = (); my @file_src = (); &arg_cmd_init(); # ...open output file if needed... binmode(STDOUT, ":utf8"); if((my $o = &arg_cmd_fetch({ arg => '-of' }))) { if(!open(STDOUT, '>', "$o")) { &msg_fail({ mess => "Failed to open output file '" . $o . "': " . $! }); } } # ...and start processing input files # if(@{ $arg_store{'ano_sources'} } > 0) { &ano_hdr({ this => $0, file => $arg_store{'ano_sources'} }); foreach my $f (@{ $arg_store{'ano_sources'} }) { &ano_get({ file => $f }); } # my $c = @dsl_cmd_r; &ano_bgn(); foreach my $d (@dsl_cmd_r) { # This is high level statement... # if($d =~ /^\s/) { print STDOUT "\t" . "/*" . $d . " */" . "\n"; next; } # ...this is C-preprocessor directive... # if($d =~ /^#/) { print STDOUT $d . "\n"; next; } # ...and this is not # print STDOUT "\t" . "{ " . $d . " }," . "\n"; } &ano_ftr({ cnt => $c }); &ano_end({ cnt => $c, ano => @{ $arg_store{'ano_sources'} }[0] }); } else { # Output skeleton program by default # &ano_out_min(); } # if(&arg_cmd_fetch({ arg => '-dv' })) { foreach my $k (sort { lc($a) cmp lc($b) } keys %var_these) { if(@{ $var_these{$k} }) { print STDERR $k . ":" . "\n"; foreach my $i (@{ $var_these{$k} }) { print STDERR "\t" . $i . "\n"; } } } } if(&alt_flags_check({ flag => 'VAR_WARN_UNUSED' })) { foreach my $k (sort { lc($a) cmp lc($b) } keys %var_usage) { if($var_usage{$k} == 1) { &msg_warn({ mess => "Variable '" . $k . "' used only once" }); } } } exit(0); sub ano_pre { my ($arg) = @_; my $r = 0; my $k = ""; for(my $i = 0; $i < @{ $arg->{file} }; $i++) { my $f = @{ $arg->{file} }[$i]; $f =~ s/\r+|\n+//g; # Some people tend to put ; at the end of the line # $f =~ s/\s+$//; $f =~ s/;+$//; $f =~ s/^\s+//; $f =~ s/\s+$//; next if($f eq ""); # Check if this is multiline... # if($f =~ /\\$/) { $f =~ s/\\$//; $k .= $f; next; } else { $k .= $f; } # ...and then for header tags... # if($k =~ /^;/) { $k =~ s/^;\s*//; next if($k eq ""); if($k =~ /^\@ANO_FLAGS_/i) { my @k = split(/\s+/, $k, 2); $alt_flags{uc($k[0])} = $k[1] if($k[1]); } elsif($k =~ /^\@ANO_SCRIPT_/i || $k =~ /^\@TAG_/i) { my @k = split(/\s+/, $k, 2); $alt_store{uc($k[0])} = $k[1] if($k[1]); } elsif($k =~ /^\@ANO_FN_NAMED_PARAMS/i) { # Get named parameter definitions from user supplied file # $k =~ s/\@.*?\s+//; # Split by comma, but not by commas inside quotes # foreach my $p (&ano_out_par_split({ this => $k, mark => ',' })) { $p =~ s/^[=;]+\s*//; &alt_par_names({ file => $p, line => ($i + 1) }); } } elsif($k =~ /^\@ANO_REMOTE_FUNCS/i) { # Get remote controlled function rules # $k =~ s/\@.*?\s+//; # Split by comma, but not by commas inside quotes # foreach my $p (ano_out_par_split({ this => $k, mark => ',' })) { $p =~ s/^[=;]+\s*//; my @p = split(/\s*=\s*/, $p); if(@p != 2) { &msg_fail({ mess => "Syntax error in remote definition '" . $p . "'", line => ($i + 1) }); return; } else { $p[0] =~ s/^.*?"//; $p[1] =~ s/\s+//; if(!$alt_zapper{$p[1]}) { &msg_fail({ mess => "Syntax error in remote definition '" . $p[1] . "' for '" . $p[0] . "'", line => ($i + 1) }); return; } $alt_remote{$p[0]} = $alt_zapper{$p[1]}; } } } elsif($k =~ /^\@ANO_UNVEIL_FILES/i) { # Get paths to be used later by unveil() # $k =~ s/\@.*?\s+//; # Split by comma, but not by commas inside quotes # foreach my $p (ano_out_par_split({ this => $k, mark => ',' })) { $p =~ s/^[=;]+\s*//; my @p = split(/\s*=\s*/, $p); if(@p != 2) { &msg_fail({ mess => "Syntax error in unveil definition '" . $p . "'", line => ($i + 1) }); return; } else { $p[0] =~ s/^.*?"//; $p[1] =~ s/\s+//; if($p[1] !~ /^[rwxc]+$/i) { &msg_fail({ mess => "Syntax error in unveil definition '" . $p[1] . "' for '" . $p[0] . "'", line => ($i + 1) }); return; } $alt_unveil{$p[0]} = $p[1]; } } } $k = ""; next; } my ($c, $p) = split(/\s+|\(/, $k, 2); # ...and then possible preprocessor commands # if($k =~ /^\b(include)\b\s+"(.*?)"/i) { my ($t) = $k =~ /"(.*?)"/; &ano_get({ file => $t, line => ($i + 1) }); } elsif($k =~ /^\b(define)\b\s+\b[a-zA-Z0-9_]+\b\s+\(.*?\)/i) { my ($t) = $k =~ /^\b[\w]+\b\s+\b([a-zA-Z0-9_]+)\b\s+/i; my ($u) = $k =~ /\(\s*(.*)\s*\)/; $u =~ s/^\s*//g; $u =~ s/\s*$//g; &ano_pre_define({ def => $t, val => $u, line => ($i + 1) }); } elsif($k =~ /^\b(proto)\b\s+\b[a-zA-Z]+\b\s+/i) { my ($t) = $k =~ /\s+(.*)$/; &ano_pre_proto({ what => $t, line => ($i + 1) }); } # $k = ""; $r = &ano_cmd({ cmd => $c, par => $p, cnt => $cnt_i++, file => $arg->{file}, line => ($i + 1) }); $cnt_i += $r; } # Open blocks must be zero at the end of script # if($var_loops != 0 || $var_funcs != 0) { if($var_loops == 1) { &msg_fail({ mess => "Unterminated block at the end of the script" }); return; } elsif($var_loops != 0) { &msg_fail({ mess => $var_loops . " unterminated blocks at the end of the script" }); return; } &msg_fail({ mess => "Unterminated block or statement at the end of the script" }); return; } # Dump possibly processed source if requested # if(&arg_cmd_fetch({ arg => '-ds' })) { if(&arg_cmd_fetch({ arg => '-dn' })) { my $n = length(scalar(@{ $arg->{file} })) + 1; for(my $i = 0; $i < @{ $arg->{file} }; $i++) { print STDERR ($i + 1) . " " x ($n - length($i + 1)) . @{ $arg->{file} }[$i]; } } else { print STDERR join("", @{ $arg->{file} }); } } } sub ano_get { my ($arg) = @_; my %m = (); # my $p = 0; $p = $arg->{line} if($arg->{line}); # if(!$arg->{file}) { &msg_fail({ mess => "Please provide source file to process", line => $p }); return; } if(!stat($arg->{file})) { &msg_fail({ mess => "Failed to open source file '" . $arg->{file} . "'", line => $p }); return; } # Try to detect include loop first... # push @file_inc, $arg->{file}; for(my $i = 0; $i < @file_inc; $i++) { if(defined($file_inc[$i + 1]) && $m{$file_inc[$i + 1]}) { &msg_fail({ mess => "Include loop detected, '" . $file_inc[$i] . "' to include '" . $arg->{file} . "'", line => $p }); return; } $m{$file_inc[$i]} = 1; } # ...then open and process the file # if(open(FILE, '<:encoding(UTF-8)', $arg->{file})) { @file_src = ; close(FILE); } else { &msg_fail({ mess => "Failed to open file '" . $arg->{file} . "': " . $!, line => $p }); return; } # Put predefines macros in front of script... # if(@pre_inc_n) { splice(@file_src, 0, 0, @pre_inc_n); # ...but not with another file, like included one # undef(@pre_inc_n); } &ano_pre({ file => \@file_src }); undef(@file_src); } # sub ano_cmd { my ($arg) = @_; # Command aliases # my %d = ( ':' => 'label', 'get' => 'fetch', 'put' => 'deliver', 'let' => 'var' ); # if($arg->{cmd} =~ /\b(define)\b/i || $arg->{cmd} =~ /\b(include)\b/i || $arg->{cmd} =~ /\b(proto)\b/i) { # Prevent command counter from increasing # return -1; } # my $c = $arg->{cmd}; $c = $d{$c} if($d{$c}); return &ano_cmd_cmd_op({ cmd => $c, par => $arg->{par}, cnt => $arg->{cnt}, file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_cmd_op { my ($arg) = @_; my $r = 0; my $s = "ano_cmd_" . $arg->{cmd}; # This is just for storing statement name # my $c = ""; if($arg->{par}) { $c = $arg->{par}; $c =~ s/\s*{+$//; $c =~ s/\s*\(.*$//; $c =~ s/\s*\[.*$//; } # Handle structure contents here... # if($on_struct != 0) { if($arg->{cmd} =~ /^}$/) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_struct_end({ cmd => lc($arg->{cmd}), file => $arg->{file}, line => $arg->{line} }); } else { &ano_cmd_call_struct_op({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); # Dont increase global command counter with structure items # $r = -1; } return $r; } # ...and commands here # if($arg->{cmd} =~ /\b(loop)\b/i || $arg->{cmd} =~ /\b(for)\b/i || $arg->{cmd} =~ /\b(while)\b/i || $arg->{cmd} =~ /\b(do)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; # These are abstract keywords and need for special processing... # &ano_cmd_call_loops({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(break)\b/i || $arg->{cmd} =~ /\b(next)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_jumps({ cmd => lc($arg->{cmd}), file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(switch)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_switch({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(case)\b/i || $arg->{cmd} =~ /\b(default)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_cases({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(try)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_tries({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(catch)\b/i || $arg->{cmd} =~ /\b(finally)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_catch({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(throw)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_throw({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(synchronize)\b/i || $arg->{cmd} =~ /\b(synchronized)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_sync({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(sighandler)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . " " . $c . ", cmd_" . $arg->{cnt}; &ano_cmd_call_sighandler({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(callback)\b/i || $arg->{cmd} =~ /\b(function)\b/i || $arg->{cmd} =~ /\b(alarm)\b/i || $arg->{cmd} =~ /\b(thread)\b/i || $arg->{cmd} =~ /\b(trigger)\b/i || $arg->{cmd} =~ /\b(trigger_eval)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . " " . $c . ", cmd_" . $arg->{cnt}; &ano_cmd_call_funcs({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(main)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_mains({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(finalize)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_final({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(hook)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_hooks({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(struct)\b/i || $arg->{cmd} =~ /\b(structure)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_struct({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b([\w+_]*enabled)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_debug({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b(if)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_ifjump({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /\b([\w+_]*if_null)\b/i || $arg->{cmd} =~ /\b([\w+_]*unless_null)\b/i || $arg->{cmd} =~ /\b([\w+_]*if_invalid)\b/i || $arg->{cmd} =~ /\b([\w+_]*unless_invalid)\b/i || $arg->{cmd} =~ /\b([\w+_]*if_zero)\b/i || $arg->{cmd} =~ /\b([\w+_]*unless_zero)\b/i) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; &ano_cmd_call_tests({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /^}$/) { push @dsl_cmd_r, " " . lc($arg->{cmd}) . ", cmd_" . $arg->{cnt}; # ...so is this... # &ano_cmd_call_end({ cmd => lc($arg->{cmd}), file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /^&[\w]+/i) { # ...this is shortcut to function call... # &ano_cmd_call_sc_call({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif($arg->{cmd} =~ /^@[\w]+/i) { # ...and this is shortcut to thread spawn... # &ano_cmd_call_sc_thread({ cmd => lc($arg->{cmd}), par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } elsif(defined &$s) { # ...here is ordinary instruction... # if($arg->{cmd} =~ /_/) { &msg_fail({ mess => "Function name '" . $arg->{cmd} . "' is reserved and cannot be used in this context", line => $arg->{line} }); return; } &$s({ cmd => lc($arg->{cmd}), par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); push @dsl_cmd_r, "DSL_COMMAND_" . uc($arg->{cmd}) . ", &dsl_cmd_" . $arg->{cnt}; } else { # ...and treat unknown instruction as function call... # if($arg->{cmd} =~ /[\w]+:+$/i || ($arg->{cmd} =~ /[\w]+/i && ($arg->{par} && $arg->{par} =~ /^:+$/))) { &ano_cmd_call_alias({ cmd => $arg->{cmd}, file => $arg->{file}, line => $arg->{line} }); } else { # ...but only if it does not look like an alias to label # &ano_cmd_call_fnc({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); push @dsl_cmd_r, " " . lc($arg->{cmd}) . "(), cmd_" . $arg->{cnt}; push @dsl_cmd_r, "DSL_COMMAND_FUNC, &dsl_cmd_" . $arg->{cnt}; # Append end instruction next to exit() function call # if($arg->{cmd} =~ /\b(exit)\b/i) { $arg->{cnt}++; &ano_cmd_end({ cmd => "end", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); push @dsl_cmd_r, " end automatically added after exit(), cmd_" . $arg->{cnt}; push @dsl_cmd_r, "DSL_COMMAND_END, &dsl_cmd_" . $arg->{cnt}; $r = 1; } } } return $r; } # sub ano_pre_define { my ($arg) = @_; if(!$arg->{val}) { undef($var_const{$arg->{def}}); } else { if(defined($var_const{$arg->{def}})) { &msg_warn({ mess => $arg->{def} . " is already defined, overwriting '" . $var_const{$arg->{def}} . "' with '" . $arg->{val} . "'", line => $arg->{line} }); } $var_const{$arg->{def}} = $arg->{val}; } } sub ano_pre_proto { my ($arg) = @_; my ($c, $d) = split(/\s+/, $arg->{what}, 2); if($c =~ /\b(callback)\b/i || $c =~ /\b(function)\b/i) { my ($f) = $d =~ /\b([\w]+)\b/i; my ($p) = $d =~ /\((.*)\)/; $fnc_proto{$f} = (); if($p) { foreach my $e (split(/,\s*/, $p)) { push @{ $fnc_proto{$f} }, $e; } } } else { &msg_fail({ mess => "Unknown proto definition '" . $c . "'", line => $arg->{line} }); return; } } # sub ano_cmd_abs { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_add { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_call { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my %p = (); my $c = $arg->{cnt}; my $d = $arg->{cmd}; my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); # Construct parameters to pass to label # my @p = (); my $i = 1; if($h && $h ne "") { $h =~ s/\s*\)\s*$//; # Split by comma, but not by commas inside quotes # # foreach my $p (&ano_out_par_split({ this => $h, mark => ','})) { foreach my $p (split(/\s?,\s?(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, $h)) { # Record possible named parameter for prototype check later # if($p =~ /^[\w]+\s*:\s*/i) { my ($e, $f) = split(/\s*:\s*/, $p, 2); if($p{$e}) { &msg_fail({ mess => "Prototyped parameter '" . $e . "' is already set for '" . $g . "'", line => $arg->{line} }); return; } $p{$e} = $i; $p = $f; } my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $p, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, rpn => $r }); push @p, $t . ":n:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_STRING") { # Remove possible casting and quotes at this point # $v =~ s/^.*?['"]//; $v =~ s/['"]\s*$//; &ano_out_par_string({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_BLOB") { &ano_out_par_blob({ cmd => $d, val => $v, mod => $r, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":b:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINTER") { &ano_out_par_pointer({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":p:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_HANDLE") { &ano_out_par_handle({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":h:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_COLOR") { &ano_out_par_color({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":c:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_IMAGE") { &ano_out_par_image({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":m:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINT") { &ano_out_par_point({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":t:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $d . "_param_v dsl_cmd_" . $d . "_param_v_" . $c . "_" . $i . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "\t" . ", NULL" . "\n"; print STDOUT "};" . "\n\n"; push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } $i++; } print STDOUT "static struct dsl_cmd_" . $d . "_param dsl_cmd_" . $d . "_q_" . $c . "[" . $i . "] = {" . "\n"; foreach my $p (@p) { my ($e, $f, $g, $h) = split(/:/, $p); print STDOUT "\t" . "{ " . $e . ", &dsl_cmd_" . $d . "_param_" . $f . "_" . $g . "_" . $h . " }," . "\n"; } print STDOUT "\t" . "{ DSL_PARAM_TYPE_NONE, NULL }" . "\n"; print STDOUT "};" . "\n\n"; } # Try to guess destination label type # if($g =~ /^['"](.*)['"]$/) { # This is quoted string... # } elsif($g =~ /^[\w]+$/i) { # ...this is non-quoted... # $g = '"' . $g; $g = $g . '"'; } elsif($g =~ /^\[\s*var\s*\]\s*[\w]+$/i) { # ...and this is meant to be a variable # $g =~ s/^\[[\w]+\]\s*//i; } else { &msg_fail({ mess => "Parameter format is unknown for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct label name to call # @p = (); my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $g, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_STRING") { # Remove possible casting and quotes at this point # $v =~ s/^.*?['"]//; $v =~ s/['"]\s*$//; &ano_out_par_string({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $d . "_v dsl_cmd_" . $d . "_v_" . $c . "_" . $i . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "\t" . ", NULL" . "\n"; print STDOUT "};" . "\n\n"; push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Check parameters against possible prototype # if(&alt_flags_check({ flag => 'USE_PROTOS' })) { &ano_cmd_call_op({ what => $v, this => \%p, slot => $i, line => $arg->{line} }); } # my ($e, $f, $u, $w) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . "," . "\n"; print STDOUT "\t" . "0, 0," . "\n"; print STDOUT "\t" . "&dsl_cmd_" . $d . "_" . $f . "_" . $u . "_" . $w . "," . "\n"; if($h && $h ne "") { print STDOUT "\t" . "dsl_cmd_" . $d . "_q_" . $c . "\n"; } else { print STDOUT "\t" . "NULL" . "\n"; } print STDOUT "};" . "\n\n"; } sub ano_cmd_call_op { my ($arg) = @_; if($fnc_proto{$arg->{what}}) { if(@{ $fnc_proto{$arg->{what}} } != ($arg->{slot} - 1)) { &msg_fail({ mess => "Prototyped parameter count " . ($arg->{slot} - 1) . " for '" . $arg->{what} . "' does not match to prototype parameter count of " . @{ $fnc_proto{$arg->{what}} }, line => $arg->{line} }); return; } # Stop here if checking count of params is enough, not the parameters itself # return if($arg->{only}); &ano_cmd_call_at({ this => $arg->{this}, pars => \@{ $fnc_proto{$arg->{what}} }, line => $arg->{line} }); } else { # Dont whine about missing prototype, after all # #&msg_warn({ mess => "Prototype is missing for function '" . # $arg->{what} . "'", # line => $arg->{line} }); } } sub ano_cmd_call_at { my ($arg) = @_; my %c = %{ $arg->{this} }; for(my $i = 0; $i < @{ $arg->{pars} }; $i++) { if(!$c{@{ $arg->{pars} }[$i]}) { &msg_fail({ mess => "Prototype parameter '" . @{ $arg->{pars} }[$i] . "' is not defined as function parameter", line => $arg->{line} }); return; } elsif($c{@{ $arg->{pars} }[$i]} && $c{@{ $arg->{pars} }[$i]} != ($i + 1)) { &msg_fail({ mess => "Prototype parameter '" . @{ $arg->{pars} }[$i] . "' is misplaced in function parameter array", line => $arg->{line} }); return; } } } # sub ano_cmd_call_fnc { my ($arg) = @_; my $c = $arg->{cnt}; my $d = $arg->{cmd}; $d =~ s/['"]+//g; # my ($e, $f) = split(/\@/, $d, 2); $e =~ s/['"]+//g; if(!$f || ($f && $f eq "")) { $f = $e; $e = ""; } else { $f =~ s/['"]+//g; } # Force the names to be strings, even when there is variable support # $e = "\"" . $e . "\""; $f = "\"" . $f . "\""; # my $h = ""; $h = $arg->{par} if($arg->{par}); $h =~ s/^\(\s*//; $h =~ s/\s*\)\s*$//; # Construct parameters to pass to shared object... # my $i = 1; if($h ne "") { my @p = (); my %k = (); # Split by comma, but not by commas inside quotes # # foreach my $p (&ano_out_par_split({ this => $h, mark => ','})) { foreach my $p (split(/\s?,\s?(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, $h)) { if($fnc_par_n{$d}) { my $e = $fnc_par_n{$d}; my $u = $p; $u =~ s/:\s*.*$//; if(%$e{$u}) { $p =~ s/^\Q$u\E:\s*//; # Store value for this named parameter to be used later # my $t = undef(); if($fnc_par_n{$d . ":types"}) { my $v = $fnc_par_n{$d . ":types"}; if(%$v{$u}) { $t = %$v{$u}; } } $k{%$e{$u}} = &ano_cmd_call_fnc_op({ i => $i, cnt => $c, par => $p, val => $t, line => $arg->{line} }); } else { # This function has some named parameters, but not with this parameter # push @p, &ano_cmd_call_fnc_op({ i => $i, cnt => $c, par => $p, line => $arg->{line} }); } } else { # This function does not have named parameters defined # push @p, &ano_cmd_call_fnc_op({ i => $i, cnt => $c, par => $p, line => $arg->{line} }); } $i++; } # Fill empty placeholders with named parameters # foreach my $e (sort { $a <=> $b } keys %k) { if(($e - 1) > @p) { &msg_fail({ mess => "Short parameter count for function '" . $d . "'", line => $arg->{line} }); return; } my $f = $k{$e}; splice(@p, ($e - 1), 0, $f); } if($fnc_par_n{$d}) { if(@p != int(keys %{ $fnc_par_n{$d} })) { my $e = keys %{ $fnc_par_n{$d} }; &msg_fail({ mess => "Wrong number of parameters for function '" . $d . "', expected " . $e . ", got " . @p, line => $arg->{line} }); return; } } print STDOUT "static struct dsl_cmd_func_param dsl_cmd_func_q_" . $c . "[" . $i . "] = {" . "\n"; foreach my $p (@p) { my ($e, $f, $g, $h) = split(/:/, $p); print STDOUT "\t" . "{ " . $e . ", &dsl_cmd_func_param_" . $f . "_" . $g . "_" . $h . " }," . "\n"; } print STDOUT "\t" . "{ DSL_PARAM_TYPE_NONE, NULL }" . "\n"; print STDOUT "};" . "\n\n"; } # Construct shared object name to call # my @p = (); my @q = ($e, $f); foreach my $p (@q) { my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $p, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_STRING") { # Use vanilla string here because subsystem detection needs it # &ano_out_par_string_vanilla({ cmd => "func", val => $v, mod => $m, cnt => $c, i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_func_v dsl_cmd_func_v_" . $c . "_" . $i . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "\t" . ", NULL, NULL" . "\n"; print STDOUT "};" . "\n\n"; push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "'", line => $arg->{line} }); return; } $i++; } print STDOUT "static struct dsl_cmd_func dsl_cmd_" . $c . " = {" . "\n"; foreach my $p (@p) { my ($e, $f, $g, $h) = split(/:/, $p); print STDOUT "\t" . $e . ", &dsl_cmd_func_" . $f . "_" . $g . "_" . $h . "," . "\n"; } print STDOUT "\t" . "0," . "\n"; if($h && $h ne "") { print STDOUT "\t" . "dsl_cmd_func_q_" . $c . "," . "\n"; } else { print STDOUT "\t" . "NULL," . "\n"; } print STDOUT "\t" . "NULL" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_cmd_call_fnc_op { my ($arg) = @_; my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $arg->{par}, line => $arg->{line} }); # Remove possible casting and quotes at this point # $v =~ s/^.*?['"]//; $v =~ s/['"]\s*$//; if($t eq "DSL_PARAM_TYPE_NUMBER") { if($arg->{val}) { # Override number type if named parameter defines it # my $o = 'DSL_NUMBER_TYPE_' . uc($arg->{val}); if($m ne 'DSL_NUMBER_TYPE_DEFAULT' && $o ne $m) { &msg_warn({ mess => "Overwriting defined function parameter '" . $v . "' type with '" . $arg->{val} . "'", line => $arg->{line} }); } $m = $o; } &ano_out_par_number({ cmd => "func", val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $arg->{i}, rpn => $r }); return $t . ":n:" . $arg->{cnt} . ":" . $arg->{i}; } elsif($t eq "DSL_PARAM_TYPE_STRING") { if($arg->{val}) { # Override string character set if named parameter defines it # my $o = 'CHARSET_' . uc($arg->{val}); if($m ne 'CHARSET_DEFAULT' && $o ne $m) { &msg_warn({ mess => "Overwriting defined function parameter '" . $v . "' type with '" . $arg->{val} . "'", line => $arg->{line} }); } $m = $o; } &ano_out_par_string({ cmd => "func", val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $arg->{i} }); return $t . ":s:" . $arg->{cnt} . ":" . $arg->{i}; } elsif($t eq "DSL_PARAM_TYPE_BLOB") { &ano_out_par_blob({ cmd => "func", val => $v, mod => $r, cnt => $arg->{cnt}, pad => "_param", i => $arg->{i} }); return $t . ":b:" . $arg->{cnt} . ":" . $arg->{i}; } elsif($t eq "DSL_PARAM_TYPE_POINTER") { &ano_out_par_pointer({ cmd => "func", val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $arg->{i} }); return $t . ":p:" . $arg->{cnt} . ":" . $arg->{i}; } elsif($t eq "DSL_PARAM_TYPE_HANDLE") { &ano_out_par_handle({ cmd => "func", val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $arg->{i} }); return $t . ":h:" . $arg->{cnt} . ":" . $arg->{i}; } elsif($t eq "DSL_PARAM_TYPE_COLOR") { &ano_out_par_color({ cmd => "func", val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $arg->{i}, mbr => $r }); return $t . ":c:" . $arg->{cnt} . ":" . $arg->{i}; } elsif($t eq "DSL_PARAM_TYPE_IMAGE") { &ano_out_par_image({ cmd => "func", val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $arg->{i}, mbr => $r }); return $t . ":m:" . $arg->{cnt} . ":" . $arg->{i}; } elsif($t eq "DSL_PARAM_TYPE_POINT") { &ano_out_par_point({ cmd => "func", val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $arg->{i}, mbr => $r }); return $t . ":t:" . $arg->{cnt} . ":" . $arg->{i}; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_func_param_v dsl_cmd_func_param_v_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "\t" . ", NULL" . "\n"; print STDOUT "};" . "\n\n"; return $t . ":v:" . $arg->{cnt} . ":" . $arg->{i}; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "'", line => $arg->{line} }); return; } } # sub ano_cmd_call_loops { my ($arg) = @_; if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required looping block opening token '{' is missing", line => $arg->{line} }); return; } $var_loops += $arg->{par} =~ tr/{$//; my $h = $arg->{par}; $h =~ s/\s*{+$//; $h =~ s/^\s*\(\s*//; $h =~ s/\s*\)\s*$//; # Here is statement 1 (init), 2 (loop cond) and 3 (loop math) just like for() loop has # my @h = ("", "", ""); my @g = split(/\s*;\s*/, $h); if($arg->{cmd} eq "loop" || $arg->{cmd} eq "for") { if(@g > 3) { &msg_fail({ mess => "Wrong number of statements, got " . @g . ", expected 3", line => $arg->{line} }); return; } splice(@h, 0, @g, @g); @g = split(/\s*==\s*|\s*!=\s*|\s*<=\s*|\s*>=\s*|\s*<\s*|\s*>\s*/, $h[1]); } elsif($arg->{cmd} eq "while" || $arg->{cmd} eq "do") { if(@g > 1) { &msg_fail({ mess => "Wrong number of statements, got " . @g . ", expected 1", line => $arg->{line} }); return; } splice(@h, 1, @g, @g); @g = split(/\s*==\s*|\s*!=\s*|\s*<=\s*|\s*>=\s*|\s*<\s*|\s*>\s*/, $h[1]); } &ano_cmd_call_loops_op({ cmd => $arg->{cmd}, opt => \@h, cmp => \@g, file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_loops_op { my ($arg) = @_; my @d = ('==', '!=', '<=', '>=', '<', '>'); my @s = ('je', 'jne', 'jbe', 'jae', 'jb', 'ja'); # Insert exploded loop into source to be processed later... # my $c = "ano_cmd_call_loops_op_" . $arg->{cmd}; my @p = &$c({ opt => $arg->{opt} }); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined loop statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); if($arg->{opt}[1]) { for(my $i = 0; $i < @d; $i++) { my ($r) = $arg->{opt}[1] =~ /$d[$i]/; if($r) { $c = "ano_cmd_call_loops_ou_" . $arg->{cmd}; if(defined &$c) { @p = &$c({ opt => $arg->{opt}, cmp => $arg->{cmp}, jmp => $s[$i] }); my @t = split(/(?![^(]+\))\s*,\s*/, $arg->{opt}[0]); splice(@{ $arg->{file} }, $arg->{line} + @t, 0, @p); } # Store exploded loop logic and labels to be inserted to source later # $c = "ano_cmd_call_loops_os_" . $arg->{cmd}; @p = &$c({ opt => $arg->{opt}, cmp => $arg->{cmp}, jmp => $s[$i] }); $var_tails[$var_loops] = [ @p ]; &ano_cmd_call_loops_at(); return; } } &msg_fail({ mess => "Unknown condition operator '" . $arg->{opt}[1] . "'", line => $arg->{line} }); return; } $c = "ano_cmd_call_loops_ok_" . $arg->{cmd}; if(defined &$c) { @p = &$c({ opt => $arg->{opt} }); my @t = split(/(?![^(]+\))\s*,\s*/, $arg->{opt}[0]); splice(@{ $arg->{file} }, $arg->{line} + @t, 0, @p); } # Store exploded loop labels to be inserted to source later # $c = "ano_cmd_call_loops_ot_" . $arg->{cmd}; @p = &$c({ opt => $arg->{opt} }); $var_tails[$var_loops] = [ @p ]; &ano_cmd_call_loops_at(); } sub ano_cmd_call_loops_op_loop { my ($arg) = @_; # Split the init part by comma, but not by commas inside parentheses # my @t = split(/(?![^(]+\))\s*,\s*/, $arg->{opt}[0]); &ano_cmd_call_loops_ep({ par => \@t }); my @r = ( # There comes an array of opts # ": \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n" ); splice(@r, 0, 0, @t); return @r; } sub ano_cmd_call_loops_op_for { my ($arg) = @_; my @t = split(/(?![^(]+\))\s*,\s*/, $arg->{opt}[0]); &ano_cmd_call_loops_ep({ par => \@t }); my @r = ( # There comes an array of opts # ": \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n" ); splice(@r, 0, 0, @t); return @r; } sub ano_cmd_call_loops_op_while { my ($arg) = @_; my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n" ); return @r; } sub ano_cmd_call_loops_op_do { my ($arg) = @_; my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n" ); return @r; } sub ano_cmd_call_loops_os_loop { my ($arg) = @_; # Split the loop counter part by comma, but not by commas inside parentheses # my @t = split(/(?![^(]+\))\s*,\s*/, $arg->{opt}[2]); &ano_cmd_call_loops_ep({ par => \@t }); my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", # There comes an array of opts # "\t" . "cmp " . $arg->{cmp}[0] . " (" . $arg->{cmp}[1] . ")" . "\n", "\t" . $arg->{jmp} . " \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); splice(@r, 1, 0, @t); return @r; } sub ano_cmd_call_loops_os_for { my ($arg) = @_; my @t = split(/(?![^(]+\))\s*,\s*/, $arg->{opt}[2]); &ano_cmd_call_loops_ep({ par => \@t }); my @r = ( # There comes an array of opts # "\t" . "jmp \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); splice(@r, 0, 0, @t); return @r; } sub ano_cmd_call_loops_ou_for { my ($arg) = @_; my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", "\t" . "cmp " . $arg->{cmp}[0] . " (" . $arg->{cmp}[1] . ")" . "\n", "\t" . $arg->{jmp} . " \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n", "\t" . "jmp \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); return @r; } sub ano_cmd_call_loops_os_while { my ($arg) = @_; my @r = ( "\t" . "jmp \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); return @r; } sub ano_cmd_call_loops_ou_while { my ($arg) = @_; my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", "\t" . "cmp " . $arg->{cmp}[0] . " (" . $arg->{cmp}[1] . ")" . "\n", "\t" . $arg->{jmp} . " \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n", "\t" . "jmp \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); return @r; } sub ano_cmd_call_loops_os_do { my ($arg) = @_; my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", "\t" . "cmp " . $arg->{cmp}[0] . " (" . $arg->{cmp}[1] . ")" . "\n", "\t" . $arg->{jmp} . " \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); return @r; } sub ano_cmd_call_loops_ot_loop { my ($arg) = @_; # Split the loop counter part by comma, but not by commas inside parentheses # my @t = split(/(?![^(]+\))\s*,\s*/, $arg->{opt}[2]); &ano_cmd_call_loops_ep({ par => \@t }); my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", # There comes an array of opts # ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); splice(@r, 1, 0, @t); return @r; } sub ano_cmd_call_loops_ot_for { my ($arg) = @_; my @r = ( "\t" . "jmp \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); return @r; } sub ano_cmd_call_loops_ot_while { my ($arg) = @_; my @r = ( "\t" . "jmp \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); return @r; } sub ano_cmd_call_loops_ot_do { my ($arg) = @_; my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); return @r; } sub ano_cmd_call_loops_ok_for { my ($arg) = @_; my @t = split(/(?![^(]+\))\s*,\s*/, $arg->{opt}[2]); &ano_cmd_call_loops_ep({ par => \@t }); my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n" # There comes an array of opts ); splice(@r, 1, 0, @t); return @r; } sub ano_cmd_call_loops_ok_while { my ($arg) = @_; my @r = ( ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n" ); return @r; } sub ano_cmd_call_loops_ec { my ($arg) = @_; $arg->{file}[$arg->{line} - 1] =~ s/^/;/; if($arg->{line} > 1) { for(my $i = $arg->{line} - 2; $i >= 0; $i--) { if($arg->{file}[$i] =~ /\\\s*$/) { $arg->{file}[$i] =~ s/^/;/; } else { last; } } } } sub ano_cmd_call_loops_ep { my ($arg) = @_; # Improve readability in case of source needs to be displayed # for(my $i = 0; $i < @{ $arg->{par} }; $i++) { $arg->{par}[$i] = "\t" . $arg->{par}[$i] . "\n"; } } sub ano_cmd_call_loops_at { my ($arg) = @_; $var_jumps[$var_loops] = [ "__for_" . $var_label . "_" . $var_loops ]; } # sub ano_cmd_call_jumps { my ($arg) = @_; my %p = ( 'break' => '_c', 'next' => '_b' ); if($var_loops == 0) { &msg_fail({ mess => "Control keyword '" . $arg->{cmd} . "' can be only used within a loop, a switch or try block", line => $arg->{line} }); return; } my @p = ( "\t" . "jmp " . "\"@{ $var_jumps[$var_loops] }" . $p{$arg->{cmd}} . "\"" . "\n" ); # Insert substituted jump keyword into source... # splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment jump keyword out # $arg->{file}[$arg->{line} - 1] =~ s/^/;/; } # sub ano_cmd_call_switch { my ($arg) = @_; if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required switch block opening token '{' is missing", line => $arg->{line} }); return; } $var_loops += $arg->{par} =~ tr/{$//; my $h = $arg->{par}; $h =~ s/\s*{+$//; $h =~ s/^\s*\(\s*//; $h =~ s/\s*\)\s*$//; # Insert default labels just in case someone adventurous try to use next keyword # my @p = ( ": \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); # Store switch statement by level for later use with cases # $var_incmp{$var_loops} = $h; @p = ( ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); $var_tails[$var_loops] = [ @p ]; $var_cases{$var_loops} = 1; } sub ano_cmd_call_cases { my ($arg) = @_; my @p = (); if($arg->{cmd} eq "case") { my $h = $arg->{par}; $h =~ s/\s*:\s*$//; @p = ( ": \"__for_" . $var_label . "_" . $var_loops . "_" . $var_cases{$var_loops} . "\"" . "\n", "\t" . "cmp " . $var_incmp{$var_loops} . " (" . $h . ")" . "\n", "\t" . "jne \"__for_" . $var_label . "_" . $var_loops . "_" . ++$var_cases{$var_loops} . "\"" . "\n" ); } else { @p = ( ": \"__for_" . $var_label . "_" . $var_loops . "_" . $var_cases{$var_loops} . "\"" . "\n" ); } splice(@{ $arg->{file} }, $arg->{line}, 0, @p); &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); &ano_cmd_call_loops_at(); } # sub ano_cmd_call_tries { my ($arg) = @_; if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required try block opening token '{' is missing", line => $arg->{line} }); return; } $var_loops += $arg->{par} =~ tr/{$//; my $h = $arg->{par}; $h =~ s/\s*{+$//; $h =~ s/^\s*\(\s*//; $h =~ s/\s*\)\s*$//; $h = "rc" if(!$h); # Store default target for throwing error # $var_throw{$var_loops} = "__for_" . $var_label. "_" . $var_loops . "_1"; # Insert default labels just in case someone adventurous try to use next keyword # my @p = ( ": \"__for_" . $var_label . "_" . $var_loops . "_a\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_b\"" . "\n", "\t" . "mov " . $h . " ([int] 0)" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); # Store try statement by level for later use if there is no finally keyword declared # $var_invar{$var_loops} = $h; @p = ( ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); $var_tails[$var_loops] = [ @p ]; $var_tries{$var_loops} = 1; } sub ano_cmd_call_catch { my ($arg) = @_; my @p = (); my @t = (); # Check if this is first catch/finally for this try or not... # if(!$var_intry{$var_loops}) { # ...and if it is, put some instructions at the end of try statement # @t = ( "\t" . "cmp " . $var_invar{$var_loops} . " ([int] 0)" . "\n", "\t" . "je \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); $var_intry{$var_loops} = 1; } if($arg->{cmd} =~ /\b(catch)\b/) { my $h = $arg->{par}; if($h) { # Here is (conditional) statement... # $h =~ s/^\(\s*//; $h =~ s/\s*:\s*$//; $h =~ s/\s*\)\s*$//; my @h = split(/\s*==\s*|\s*!=\s*|\s*<=\s*|\s*>=\s*|\s*<\s*|\s*>\s*/, $h); my @r = &ano_cmd_call_catch_op({ opt => $h, cmp => \@h, file => $arg->{file}, line => $arg->{line} }); @p = ( @t, ": \"__for_" . $var_label . "_" . $var_loops . "_" . $var_tries{$var_loops} . "\"" . "\n", @r ); } else { # ...and here is not # $h = "[int] 0"; @p = ( @t, ": \"__for_" . $var_label . "_" . $var_loops . "_" . $var_tries{$var_loops} . "\"" . "\n", "\t" . "cmp " . $var_invar{$var_loops} . " (" . $h . ")" . "\n", "\t" . "je \"__for_" . $var_label . "_" . $var_loops . "_" . ($var_tries{$var_loops} + 1) . "\"" . "\n" ); } $var_tries{$var_loops}++; } else { undef($var_tails[$var_loops]); @p = ( @t, ": \"__for_" . $var_label . "_" . $var_loops . "_" . $var_tries{$var_loops} . "\"" . "\n", ": \"__for_" . $var_label . "_" . $var_loops . "_c\"" . "\n" ); } splice(@{ $arg->{file} }, $arg->{line}, 0, @p); &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); &ano_cmd_call_loops_at(); } sub ano_cmd_call_catch_op { my ($arg) = @_; my @d = ('==', '!=', '<=', '>=', '<', '>'); my @s = ('jne', 'je', 'ja', 'jb', 'jae', 'jbe'); my $c = 'jne'; my $d = $var_invar{$var_loops}; my $e = $arg->{opt}; if(@{ $arg->{cmp} } == 2) { for(my $i = 0; $i < @d; $i++) { my ($r) = $arg->{opt} =~ /$d[$i]/; if($r) { $c = $s[$i]; last; } } $d = $arg->{cmp}[0]; $e = $arg->{cmp}[1]; } elsif(@{ $arg->{cmp} } != 1) { &msg_fail({ mess => "Unknown condition '" . $arg->{opt} . "'", line => $arg->{line} }); return; } my @r = ( "\t" . "cmp " . $d . " (" . $e . ")" . "\n", "\t" . $c . " \"__for_" . $var_label . "_" . $var_loops . "_" . ($var_tries{$var_loops} + 1) . "\"" . "\n" ); return @r; } sub ano_cmd_call_throw { my ($arg) = @_; my @p = (); if(!$var_throw{$var_loops}) { &msg_fail({ mess => "Unknown throw label", line => $arg->{line} }); return; } my $h = $arg->{par}; if($h) { $h =~ s/^\(\s*//; $h =~ s/\s*:\s*$//; $h =~ s/\s*\)\s*$//; @p = ( "\t" . "mov " . $var_invar{$var_loops} . " (" . $h . ")" . "\n", "\t" . "jmp \"" . $var_throw{$var_loops} . "\"" . "\n" ); } else { @p = ( "\t" . "jmp \"" . $var_throw{$var_loops} . "\"" . "\n" ); } splice(@{ $arg->{file} }, $arg->{line}, 0, @p); &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); } # sub ano_cmd_call_sync { my ($arg) = @_; if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required synchronized block opening token '{' is missing", line => $arg->{line} }); return; } $var_loops += $arg->{par} =~ tr/{$//; # Check if this statement has valid attributes... # my $r; my ($n) = $arg->{par} =~ /\s*\[\s*(.*)\s*\]\s*/; if($n) { $r = &ano_cmd_call_funcs_op({ cmd => $arg->{cmd}, fnc => $arg->{cmd}, par => $n, file => $arg->{file}, line => $arg->{line} }); } # ...and if not, use default oid value # $r = 0 if(!$r); # Insert sync entry function call into source... # my @p = ( "\t" . "enter [int] " . $r . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); # Store sync exit function call for later use # @p = ( "\t" . "leave [int] " . $r . "\n" ); $var_tails[$var_loops] = [ @p ]; } sub ano_cmd_call_funcs_at_synchronized_oid { my ($arg) = @_; my $r = &ano_cmd_call_funcs_at_number({ cmd => $arg->{cmd}, opt => $arg->{opt}, line => $arg->{line} }); return $r; } # sub ano_cmd_call_sighandler { my ($arg) = @_; my %c = ( 'hup' => 1, 'int' => 1, 'term' => 1, 'quit' => 1, 'usr1' => 1, 'usr2' => 1 ); if($var_funcs != 0) { &msg_fail({ mess => "Signal handler block does not support nesting", line => $arg->{line} }); return; } if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required signal handler block opening token '{' is missing", line => $arg->{line} }); return; } # Get possible attributes... # my ($n) = $arg->{par} =~ /\s*\[\s*(.*)\s*\]\s*/; $arg->{par} =~ s/\s*\[\s*.*\s*\]\s*//; # ...and make some cleanup # my $g = $arg->{par}; $g =~ s/^\s+//; $g =~ s/\s*{$//; $g =~ s/['"]+//g; if(!$c{lc($g)}) { &msg_fail({ mess => "Signal name '" . $g . "' is unknown", line => $arg->{line} }); return; } # Check if this statement had valid attributes # if($n) { my $r = &ano_cmd_call_funcs_op({ cmd => $arg->{cmd}, fnc => $g, par => $n, file => $arg->{file}, line => $arg->{line} }); } # Insert converted label instruction into source... # splice(@{ $arg->{file} }, $arg->{line}, 0, ": \"__sighandler_" . lc($g) . "\"" . "\n"); # ...and comment possibly multilined function statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); $var_funcs = 1; } # sub ano_cmd_call_funcs { my ($arg) = @_; if($var_funcs != 0) { &msg_fail({ mess => "Function block does not support nesting", line => $arg->{line} }); return; } if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required function block opening token '{' is missing", line => $arg->{line} }); return; } # Get possible attributes... # my ($n) = $arg->{par} =~ /\s*\[\s*(.*)\s*\]\s*/; $arg->{par} =~ s/\s*\[\s*.*\s*\]\s*//; # ...and make some cleanup # my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); $g =~ s/^\s+//; $g =~ s/\s*{$//; $g =~ s/['"]+//g; # Check if this statement had valid attributes... # if($n) { my $r = &ano_cmd_call_funcs_op({ cmd => $arg->{cmd}, fnc => $g, par => $n, file => $arg->{file}, line => $arg->{line} }); } # ...and produce valid label # $g = "\"" . $g if($g !~ /^['"]/); $g = $g . "\"" if($g !~ /['"]$/); $h =~ s/\s*{$// if($h); if($h && $h ne "") { $g = $g . " (" . $h; } if($arg->{cmd} eq "callback" || $arg->{cmd} eq "alarm" || $arg->{cmd} eq "thread") { $var_funcs = 1; } elsif($arg->{cmd} eq "function") { $var_funcs = 2; } elsif($arg->{cmd} eq "trigger" || $arg->{cmd} eq "trigger_eval") { # Insert trigger label prefix to variable name # $g =~ s/^['"]/$&__$arg->{cmd}_/; $var_funcs = 1; } # Insert converted label instruction into source... # splice(@{ $arg->{file} }, $arg->{line}, 0, ": " . $g . "\n"); # ...and comment possibly multilined function statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_funcs_op { my ($arg) = @_; my $r; if($arg->{par}) { my @p = split(/\s*,\s*/, $arg->{par}); foreach my $p (@p) { my ($e, $o) = split(/\s*[:=]\s*/, $p, 2); my $f = "ano_cmd_call_funcs_at_" . $arg->{cmd} . "_" . lc($e); if(defined &$f) { $r = &$f({ cmd => $e, fnc => $arg->{fnc}, opt => $o, file => $arg->{file}, line => $arg->{line} }); } else { &msg_fail({ mess => "Unknown attribute '" . $e . "' for statement '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } } return $r; } sub ano_cmd_call_funcs_at_callback_entry { my ($arg) = @_; # Insert function call to source # my @p = ( "\t" . "jmp \"" . lc($arg->{opt}) . "\"" . "\n", ": " . "\"" . lc($arg->{opt}) . "_ret\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return 1; } sub ano_cmd_call_funcs_at_callback_return { my ($arg) = @_; # Store function call to be inserted later # my @p = ( "\t" . "jmp \"" . lc($arg->{opt}) . "\"" . "\n", ": " . "\"" . lc($arg->{opt}) . "_ret\"" . "\n" ); push @var_hooks, @p; return 1; } sub ano_cmd_call_funcs_at_callback_remote { my ($arg) = @_; return &ano_cmd_call_funcs_at_function_remote({ cmd => $arg->{cmd}, fnc => $arg->{fnc}, opt => $arg->{opt}, file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_funcs_at_function_entry { my ($arg) = @_; # Insert function call to source # my @p = ( "\t" . "jmp \"" . lc($arg->{opt}) . "\"" . "\n", ": " . "\"" . lc($arg->{opt}) . "_ret\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return 1; } sub ano_cmd_call_funcs_at_function_return { my ($arg) = @_; # Store function call to be inserted later # my @p = ( "\t" . "jmp \"" . lc($arg->{opt}) . "\"" . "\n", ": " . "\"" . lc($arg->{opt}) . "_ret\"" . "\n" ); push @var_hooks, @p; return 1; } sub ano_cmd_call_funcs_at_function_remote { my ($arg) = @_; if(!$alt_zapper{$arg->{opt}}) { &msg_fail({ mess => "Proper keyword was expected with attribute '" . $arg->{cmd} . "', got '" . $arg->{opt} . "'", line => $arg->{line} }); return; } $alt_remote{$arg->{fnc}} = $alt_zapper{$arg->{opt}}; } sub ano_cmd_call_funcs_at_alarm_repeat { my ($arg) = @_; my $r = &ano_cmd_call_funcs_at_number({ cmd => $arg->{cmd}, opt => $arg->{opt}, line => $arg->{line} }); # Insert function call to source # my @p = ( "\t" . "var [number] __c_" . lc($arg->{fnc}) . "\n", "\t" . "toulong __c_" . lc($arg->{fnc}) . "\n", "\t" . "cmp __c_" . lc($arg->{fnc}) . " ([ulong] " . $r . ")" . "\n", "\t" . "jne \"__" . lc($arg->{fnc}) . "\"" . "\n", "\t" . "timer ([long] 0, [long] 0, \"" . lc($arg->{fnc}) . "\")" . "\n", "\t" . "end" . "\n", ": \"__" . lc($arg->{fnc}) . "\"" . "\n", "\t" . "inc __c_" . lc($arg->{fnc}) . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return $r; } sub ano_cmd_call_funcs_at_alarm_respawn { my ($arg) = @_; my ($s, $n) = split(/:+/, $arg->{opt}); if($s) { $s = &ano_cmd_call_funcs_at_number({ cmd => $arg->{cmd}, opt => $s, line => $arg->{line} }); } else { $s = 0; } if($n) { $n = &ano_cmd_call_funcs_at_number({ cmd => $arg->{cmd}, opt => $n, line => $arg->{line} }); } else { $n = 0; } # Insert function call to source # my @p = ( "\t" . "timer ([long] " . $s . ", [long] " . $n . ", \"" . $arg->{fnc} . "\")" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return $s . ":" . $n; } sub ano_cmd_call_funcs_at_alarm_entry { my ($arg) = @_; # Insert function call to source # my @p = ( "\t" . "jmp \"" . lc($arg->{opt}) . "\"" . "\n", ": " . "\"" . lc($arg->{opt}) . "_ret\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return 1; } sub ano_cmd_call_funcs_at_alarm_return { my ($arg) = @_; # Store function call to be inserted later # my @p = ( "\t" . "jmp \"" . lc($arg->{opt}) . "\"" . "\n", ": " . "\"" . lc($arg->{opt}) . "_ret\"" . "\n" ); push @var_hooks, @p; return 1; } sub ano_cmd_call_funcs_at_alarm_remote { my ($arg) = @_; return &ano_cmd_call_funcs_at_function_remote({ cmd => $arg->{cmd}, fnc => $arg->{fnc}, opt => $arg->{opt}, file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_funcs_at_thread_affinity { my ($arg) = @_; my $r = &ano_cmd_call_funcs_at_number({ cmd => $arg->{cmd}, opt => $arg->{opt}, line => $arg->{line} }); # Insert function call to source # my @p = ( "\t" . "thread_affinity ([int] " . $r . ")" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return $r; } sub ano_cmd_call_funcs_at_thread_stacksize { my ($arg) = @_; my $r = &ano_cmd_call_funcs_at_number({ cmd => $arg->{cmd}, opt => $arg->{opt}, line => $arg->{line} }); # Insert function call to source # my @p = ( "\t" . "thread_stack_size ([usize] " . $r . ")" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return $r; } sub ano_cmd_call_funcs_at_thread_guardsize { my ($arg) = @_; my $r = &ano_cmd_call_funcs_at_number({ cmd => $arg->{cmd}, opt => $arg->{opt}, line => $arg->{line} }); # Insert function call to source # my @p = ( "\t" . "thread_guard_size ([usize] " . $r . ")" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return $r; } sub ano_cmd_call_funcs_at_thread_entry { my ($arg) = @_; # Insert function call to source # my @p = ( "\t" . "jmp \"" . lc($arg->{opt}) . "\"" . "\n", ": " . "\"" . lc($arg->{opt}) . "_ret\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return 1; } sub ano_cmd_call_funcs_at_thread_return { my ($arg) = @_; # Store function call to be inserted later # my @p = ( "\t" . "jmp \"" . lc($arg->{opt}) . "\"" . "\n", ": " . "\"" . lc($arg->{opt}) . "_ret\"" . "\n" ); push @var_hooks, @p; return 1; } sub ano_cmd_call_funcs_at_thread_remote { my ($arg) = @_; return &ano_cmd_call_funcs_at_function_remote({ cmd => $arg->{cmd}, fnc => $arg->{fnc}, opt => $arg->{opt}, file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_funcs_at_trigger_mode { my ($arg) = @_; my $r = 0; if($arg->{opt} =~ /^blocking$/i) { # This trigger is not threaded... # } elsif($arg->{opt} =~ /^concurrent$/i || $arg->{opt} =~ /^threaded$/i) { # ...but this is, so insert function call to source # my @p = ( "\t" . "thread_spawn (\"trigger_" . $arg->{fnc} . "_" . $var_trigs . "\", \"__trigger_" . $arg->{fnc} . "_" . $var_trigs . "\")" . "\n", "\t" . "end" . "\n", ": \"__trigger_" . $arg->{fnc} . "_" . $var_trigs . "\"" . "\n" ); $r = 1; splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # Increase global statement counter for trigger thread labels # $var_trigs++; } else { &msg_fail({ mess => "Proper keyword was expected with attribute '" . $arg->{cmd} . "', got '" . $arg->{opt} . "'", line => $arg->{line} }); return; } return $r; } sub ano_cmd_call_funcs_at_trigger_value { my ($arg) = @_; my $r = $arg->{opt}; my $c = 'je'; if($r !~ /['"](.*)['"]/ && $r !~ /^[\$\*@#%&]/) { if($r =~ /:/) { # This looks like a value range... # my @d = ('jae', 'jbe'); my @e = ('jb', 'ja'); my $f; if($r =~ /^!/) { $f = \@e; $r =~ s/^!\s*//; } else { $f = \@d; } my $j = 0; my @p = (); foreach my $i (split(/\s*:\s*/, $r)) { push @p, "\t" . "cmp " . $arg->{fnc} . " (" . $i . ")" . "\n"; push @p, "\t" . @{ $f }[$j] . " \"__trigger_" . $arg->{fnc} . "_" . $var_trigs . "\"" . "\n"; push @p, "\t" . "end" . "\n"; push @p, ": \"__trigger_" . $arg->{fnc} . "_" . $var_trigs . "\"" . "\n"; $j ^= 1; $var_trigs++; } splice(@{ $arg->{file} }, $arg->{line}, 0, @p); return 1; } else { # ...and this is probably just a single value # my @d = ('==', '=', '!=', '!', '<=', '>=', '<', '>'); my @s = ('je', 'je', 'jne', 'jne', 'jbe', 'jae', 'jb', 'ja'); my $i = 0; my $j = ""; foreach my $d (@d) { if($r =~ /^$d/) { $j = $d[$i]; last; } $i++; } if(!$s[$i]) { $i = 0; } $c = $s[$i]; $r =~ s/^$j\s*//; } } my @p = ( "\t" . "cmp " . $arg->{fnc} . " (" . $r . ")" . "\n", "\t" . $c . " \"__trigger_" . $arg->{fnc} . "_" . $var_trigs . "\"" . "\n", "\t" . "end" . "\n", ": \"__trigger_" . $arg->{fnc} . "_" . $var_trigs . "\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # Increase global statement counter for trigger labels # $var_trigs++; return 1; } sub ano_cmd_call_funcs_at_trigger_remote { my ($arg) = @_; return &ano_cmd_call_funcs_at_function_remote({ cmd => $arg->{cmd}, fnc => $arg->{fnc}, opt => $arg->{opt}, file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_funcs_at_number { my ($arg) = @_; # Check if this is valid number or rpn expression # my @t = &ano_cmd_par_op({ par => $arg->{opt}, line => $arg->{line} }); if($t[0] ne 'DSL_PARAM_TYPE_NUMBER') { &msg_fail({ mess => "Number was expected with attribute '" . $arg->{cmd} . "', got '" . $t[1] . "'", line => $arg->{line} }); return; } return $arg->{opt}; } # sub ano_cmd_call_mains { my ($arg) = @_; if($var_funcs != 0) { &msg_fail({ mess => "Main block does not support nesting", line => $arg->{line} }); return; } if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required main block opening token '{' is missing", line => $arg->{line} }); return; } # Check if this statement had valid attributes # my $r; my ($n) = $arg->{par} =~ /\s*\[\s*(.*)\s*\]\s*/; if($n) { $r = &ano_cmd_call_funcs_op({ cmd => $arg->{cmd}, fnc => $arg->{cmd}, par => $n, file => $arg->{file}, line => $arg->{line} }); } # Insert converted label instruction into source... # my @p = ( ": \"__" . $arg->{cmd} . "\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); # Store exit function call for later use only if exit code was specified # if(defined $r) { if($r =~ /^\d+$/ && $r == 0) { push @var_hooks, "\t" . "exit" . "\n"; } else { push @var_hooks, "\t" . "exit " . $r . "\n"; } } $var_funcs = 1; } sub ano_cmd_call_funcs_at_main_exit { my ($arg) = @_; my $r = &ano_cmd_call_funcs_at_number({ cmd => $arg->{cmd}, opt => $arg->{opt}, line => $arg->{line} }); return $r; } sub ano_cmd_call_funcs_at_main_remote { my ($arg) = @_; return &ano_cmd_call_funcs_at_function_remote({ cmd => $arg->{cmd}, fnc => $arg->{fnc}, opt => $arg->{opt}, file => $arg->{file}, line => $arg->{line} }); } # sub ano_cmd_call_final { my ($arg) = @_; if($var_funcs != 0) { &msg_fail({ mess => "Finalize block does not support nesting", line => $arg->{line} }); return; } if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required finalize block opening token '{' is missing", line => $arg->{line} }); return; } # Check if this statement had valid attributes # my ($n) = $arg->{par} =~ /\s*\[\s*(.*)\s*\]\s*/; if($n) { my $r = &ano_cmd_call_funcs_op({ cmd => $arg->{cmd}, fnc => $arg->{cmd}, par => $n, file => $arg->{file}, line => $arg->{line} }); } # Insert converted label instruction into source... # my @p = ( ": \"__" . $arg->{cmd} . "\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); $var_funcs = 1; } # sub ano_cmd_call_hooks { my ($arg) = @_; if($var_funcs != 0) { &msg_fail({ mess => "Hook block does not support nesting", line => $arg->{line} }); return; } if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required hook block opening token '{' is missing", line => $arg->{line} }); return; } $var_loops += $arg->{par} =~ tr/{$//; # Clean up the name to be used later # my $r = $arg->{par}; $r =~ s/\s*{+$//; # Insert converted label instruction into source... # my @p = ( ": \"" . $r . "\"" . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); # Store return jump for later use # @p = ( "\t" . "jmp " . "\"" . $r . "_ret\"" . "\n" ); $var_tails[$var_loops] = [ @p ]; } # sub ano_cmd_call_end { my ($arg) = @_; if($var_loops == 0) { # Statement is always in toplevel, not inside loops or other things # if($var_funcs == 1) { # Insert end instruction into source to terminate callback... # if(@var_hooks) { if($var_hooks[-1] !~ /\texit/) { push @var_hooks, "\t" . "end" . "\n"; } splice(@{ $arg->{file} }, $arg->{line}, 0, @var_hooks); undef(@var_hooks); } else { splice(@{ $arg->{file} }, $arg->{line}, 0, "\t" . "end" . "\n"); } # ...and comment closing keyword out # $arg->{file}[$arg->{line} - 1] =~ s/^/;/; $var_funcs = 0; return; } elsif($var_funcs == 2) { # Insert return instruction and possible hook into source to terminate function # if(@var_hooks) { push @var_hooks, "\t" . "ret" . "\n"; splice(@{ $arg->{file} }, $arg->{line}, 0, @var_hooks); undef(@var_hooks); } else { splice(@{ $arg->{file} }, $arg->{line}, 0, "\t" . "ret" . "\n"); } $arg->{file}[$arg->{line} - 1] =~ s/^/;/; $var_funcs = 0; return; } &msg_fail({ mess => "Required identifier before '}' token is missing", line => $arg->{line} }); return; } # Insert exploded loop end logic into source... # if($var_tails[$var_loops]) { if($var_tails[$var_loops][0] =~ /^#/) { # These are C-preprocessor directives... # foreach my $p (@{ $var_tails[$var_loops] }) { push @dsl_cmd_r, $p; # ...print directive out to end wrapping command structures... # print STDOUT $p . "\n\n"; } } else { # ...and these are not # splice(@{ $arg->{file} }, $arg->{line}, 0, @{ $var_tails[$var_loops] }); } } # ...and comment closing keyword out # $arg->{file}[$arg->{line} - 1] =~ s/^/;/; # Get rid of housekeeping for this block... # undef($var_incmp{$var_loops}); undef($var_intry{$var_loops}); undef($var_invar{$var_loops}); undef($var_cases{$var_loops}); undef($var_tries{$var_loops}); $var_loops -= $arg->{cmd} =~ tr/}$//; # ...and increase global statement counter for loop labels # $var_label++ if($var_loops == 0); } # sub ano_cmd_call_alias { my ($arg) = @_; my $r = $arg->{cmd}; $r =~ s/:.*$//; if($r !~ /^['"]/) { $r = '"' . $r; } if($r !~ /['"]$/) { $r = $r . '"'; } # Insert label instruction into source... # my @p = ( ": " . $r . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); } # sub ano_cmd_call_struct { my ($arg) = @_; if($var_funcs != 0) { &msg_fail({ mess => "Structure block does not support nesting", line => $arg->{line} }); return; } if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required structure block opening token '{' is missing", line => $arg->{line} }); return; } $var_loops += $arg->{par} =~ tr/{$//; # Clean up the name to be used later # my $r = $arg->{par}; $r =~ s/\s*{+$//; if($r !~ /^[a-zA-Z0-9_]+$/) { &msg_fail({ mess => "Invalid structure name '" . $r . "'", line => $arg->{line} }); return; } # Store structure name to use with member offset macros # $str_store{$r} = 1; $str_names{$r} = (); $str_these{++$on_struct} = $r; } sub ano_cmd_call_struct_op { my ($arg) = @_; # Handle stuff inside structure # my $r = $arg->{cmd}; if($arg->{par} && $arg->{par} ne "") { $r .= " " . $arg->{par}; } my ($t, $p) = split(/\s+/, $r, 2); # Loop through possible comma separated list of items # foreach my $p (&ano_out_par_split({ this => $p, mark => ',' })) { my $v; if($p =~ /=/) { # Get the initial value if there is one # ($p, $v) = split(/\s*=\s*/, $p, 2); # Check item name, it may look like 'item_name[2]' # if($p !~ /^[a-zA-Z0-9_\[\]]+$/) { &msg_fail({ mess => "Illegal char in structure member name '" . $p . "' in structure '" . $str_these{$on_struct} . "'", line => $arg->{line} }); return; } } elsif($p =~ /\s/) { ($v, $p) = split(/\s+/, $p); # Check item name, it may look like 'item_name[2]' # if($p !~ /^[a-zA-Z0-9_\[\]]+$/) { &msg_fail({ mess => "Illegal char in structure member name '" . $p . "'", line => $arg->{line} }); return; } } # push @str_items, $p; next if(&ano_cmd_call_struct_num_op({ type => $t, rest => $p, init => $v }) == 1); next if(&ano_cmd_call_struct_str_op({ type => $t, rest => $p, init => $v }) == 1); next if(&ano_cmd_call_struct_blb_op({ type => $t, rest => $p, init => $v }) == 1); next if(&ano_cmd_call_struct_ptr_op({ type => $t, rest => $p, init => $v }) == 1); next if(&ano_cmd_call_struct_hnd_op({ type => $t, rest => $p, init => $v }) == 1); next if(&ano_cmd_call_struct_clr_op({ type => $t, rest => $p, init => $v }) == 1); next if(&ano_cmd_call_struct_img_op({ type => $t, rest => $p, init => $v }) == 1); next if(&ano_cmd_call_struct_pnt_op({ type => $t, rest => $p, init => $v }) == 1); # &msg_fail({ mess => "Unknown member type '" . $t . "' in structure '" . $str_these{$on_struct} . "'", line => $arg->{line} }); return; } } sub ano_cmd_call_struct_num_op { my ($arg) = @_; my @n = ( 'number', 'num', 'int8', 'int16', 'int32', 'int64', 'int128', 'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'char', 'short', 'int', 'long', 'uchar', 'ushort', 'uint', 'ulong', 'float', 'double', 'i8', 'i16', 'i32', 'i64', 'i128', 'isize', 'u8', 'u16', 'u32', 'u64', 'u128', 'usize', 'f32', 'f64' ); my %t = ( 'number' => 'default', 'i8' => 'int8', 'i16' => 'int16', 'i32' => 'int32', 'i64' => 'int64', 'i128' => 'int128', 'u8' => 'uint8', 'u16' => 'uint16', 'u32' => 'uint32', 'u64' => 'uint64', 'u128' => 'uint128', 'f32' => 'float', 'f64' => 'double' ); return &ano_cmd_call_struct_two_op({ type => $arg->{type}, rest => $arg->{rest}, init => $arg->{init}, this => \@n, that => \%t, one => $n[0], two => 'dsl_number_type_', three => $n[1] }); } sub ano_cmd_call_struct_str_op { my ($arg) = @_; my @n = ( 'string', 'str', 'utf8', 'utf-8', 'utf32', 'utf-32' ); my %t = ( 'utf8' => 'utf-8', 'utf32' => 'utf-32' ); return &ano_cmd_call_struct_two_op({ type => $arg->{type}, rest => $arg->{rest}, init => $arg->{init}, this => \@n, that => \%t, one => $n[0], two => '', three => $n[1] }); } sub ano_cmd_call_struct_blb_op { my ($arg) = @_; my @n = ( 'blob', 'blb', 'structure', 'struct' ); my %t = ( 'structure' => 'struct' ); return &ano_cmd_call_struct_two_op({ type => $arg->{type}, rest => $arg->{rest}, init => $arg->{init}, this => \@n, that => \%t, one => $n[0], two => '', three => $n[1] }); } sub ano_cmd_call_struct_ptr_op { my ($arg) = @_; my @n = ( 'pointer', 'ptr' ); return &ano_cmd_call_struct_one_op({ type => $arg->{type}, rest => $arg->{rest}, init => $arg->{init}, this => \@n, one => $n[0], two => $n[1] }); } sub ano_cmd_call_struct_hnd_op { my ($arg) = @_; my @n = ( 'handle', 'hnd' ); return &ano_cmd_call_struct_one_op({ type => $arg->{type}, rest => $arg->{rest}, init => $arg->{init}, this => \@n, one => $n[0], two => $n[1] }); } sub ano_cmd_call_struct_clr_op { my ($arg) = @_; my @n = ( 'color', 'clr' ); return &ano_cmd_call_struct_one_op({ type => $arg->{type}, rest => $arg->{rest}, init => $arg->{init}, this => \@n, one => $n[0], two => $n[1] }); } sub ano_cmd_call_struct_img_op { my ($arg) = @_; my @n = ( 'image', 'img' ); return &ano_cmd_call_struct_one_op({ type => $arg->{type}, rest => $arg->{rest}, init => $arg->{init}, this => \@n, one => $n[0], two => $n[1] }); } sub ano_cmd_call_struct_pnt_op { my ($arg) = @_; my @n = ( 'point', 'pnt' ); return &ano_cmd_call_struct_one_op({ type => $arg->{type}, rest => $arg->{rest}, init => $arg->{init}, this => \@n, one => $n[0], two => $n[1] }); } sub ano_cmd_call_struct_one_op { my ($arg) = @_; # my $t = $arg->{type}; my $p = $arg->{rest}; my @n = @{ $arg->{this} }; # if($str_names{$str_these{$on_struct}}{$p}) { &msg_fail({ mess => "'" . $p . "' is already defined in '" . $str_these{$on_struct} . "'", line => $arg->{line} }); return 0; } # foreach my $i (@n) { if($t =~ /^$i$/i) { $str_names{$str_these{$on_struct}}{$p} = uc($arg->{one}); $str_inits{$str_where} = [ $arg->{two}, $arg->{init} ]; $str_where++; return 1; } } return 0; } sub ano_cmd_call_struct_two_op { my ($arg) = @_; # my $t = $arg->{type}; my $p = $arg->{rest}; my @n = @{ $arg->{this} }; my %u = %{ $arg->{that} }; # if($str_names{$str_these{$on_struct}}{$p}) { &msg_fail({ mess => "'" . $p . "' is already defined in '" . $str_these{$on_struct} . "'", line => $arg->{line} }); return 0; } # foreach my $i (@n) { if($t =~ /^$i$/i) { $t = $u{$t} if($u{$t}); $str_names{$str_these{$on_struct}}{$p} = uc($arg->{one}); $str_types{$str_these{$on_struct}}{$p} = uc($arg->{two}) . uc($t); $str_inits{$str_where} = [ $arg->{three}, $arg->{init} ]; $str_where++; return 1; } } return 0; } sub ano_cmd_call_struct_end { my ($arg) = @_; # Print member structures... # print STDOUT "/* Members of " . $str_these{$on_struct} . " structure */" . "\n"; for(my $i = 0; $i < @str_items; $i++) { my $n = $str_names{$str_these{$on_struct}}{$str_items[$i]}; my $t = $str_types{$str_these{$on_struct}}{$str_items[$i]}; print STDOUT "static struct dsl_" . $str_inits{$i}[0] . " __" . $str_these{$on_struct} . "_t_" . $i . " = {" . "\n"; if($n eq 'NUMBER') { print STDOUT "\t" . $t . "," . "\n"; if($str_inits{$i}[1]) { my $p = $str_inits{$i}[1]; if($p =~ /^0b[0-1_]+$/i || $p =~ /^0o[0-7_]+$/i || $p =~ /^0x[0-9a-f_]+$/i || $p =~ /^b['"](.*)['"]$/i || $p =~ /^([+-])?[0-9._]+([eE][0-9]+)?$/) { $p = &ano_cmd_par_op_number_op({ this => $p, cast => 'guess', line => $arg->{line} }); print STDOUT "\t" . "{ " . $p . " }," . "\n"; print STDOUT "\t" . "{ { { NULL, 0, 0 }, { NULL, 0, 0 } }," . "\n"; print STDOUT "\t\t" . "IS_NO, 0.0 }" . "\n"; } else { print STDOUT "\t" . "{ 0.0 }," . "\n"; print STDOUT "\t" . "{ { { (\"" . &ano_out_hex_bytes({ str => $str_inits{$i}[1] }) . "\"), " . &ano_out_len_bytes({ str => $str_inits{$i}[1] }) . ", 0 }," . "\n"; print STDOUT "\t" . "{ CHARSET_DEFAULT, " . "CHARSET_DEFAULT_SIZE, 0 } }," . "\n"; print STDOUT "\t\t" . "IS_NO, 0.0 }" . "\n"; } } else { print STDOUT "\t" . "{ 0.0 }," . "\n"; print STDOUT "\t" . "{ { { NULL, 0, 0 }, { NULL, 0, 0 } }," . "\n"; print STDOUT "\t\t" . "IS_NO, 0.0 }" . "\n"; } } elsif($n eq 'STRING') { if($str_inits{$i}[1]) { print STDOUT "\t" . "{ (\"" . &ano_out_hex_bytes({ str => $str_inits{$i}[1] }) . "\"), " . &ano_out_len_bytes({ str => $str_inits{$i}[1] }) . ", 0 }," . "\n"; } else { print STDOUT "\t" . "{ NULL, 0, 0 }," . "\n"; } if($t eq 'STRING') { print STDOUT "\t" . "{ CHARSET_DEFAULT, " . "CHARSET_DEFAULT_SIZE, 0 }" . "\n"; } else { print STDOUT "\t" . "{ (\"" . &ano_out_hex_bytes({ str => $t }) . "\"), " . &ano_out_len_bytes({ str => $t }) . ", 0 }" . "\n"; } } elsif($n eq 'BLOB') { # No support for nested structures # print STDOUT "\t" . "/* struct __" . $str_inits{$i}[1] . "_t " . $str_items[$i] . " */" . "\n"; } elsif($n eq 'POINTER') { if($str_inits{$i}[1]) { print STDOUT "\t" . "(void *) " . $str_inits{$i}[1] . "\n"; } else { print STDOUT "\t" . "NULL" . "\n"; } } elsif($n eq 'HANDLE') { if($str_inits{$i}[1]) { print STDOUT "\t" . $str_inits{$i}[1] . "\n"; } else { print STDOUT "\t" . "0" . "\n"; } } elsif($n eq 'COLOR') { if($str_inits{$i}[1]) { my @c = &ano_cmd_par_op_color({ this => $str_inits{$i}[1] }); print STDOUT "#if defined(IS_BIGENDIAN)" . "\n"; print STDOUT "\t" . "{ { { " . join(', ', split(/,/, $c[1])) . " } } }" . "\n"; print STDOUT "#else" . "\n"; print STDOUT "\t" . "{ { { " . join(', ', reverse(split(/,/, $c[1]))) . " } } }" . "\n"; print STDOUT "#endif" . "\n"; } else { print STDOUT "\t" . "{ { { 0, 0, 0, 0 } } }" . "\n"; } } elsif($n eq 'IMAGE') { if($str_inits{$i}[1]) { print STDOUT "\t" . "(\"" . &ano_out_hex_bytes({ str => $str_inits{$i}[1] }) . "\"), " . "{ 0, 0, NULL }" . "\n"; } else { print STDOUT "\t" . "NULL, { 0, 0, NULL }" . "\n"; } } elsif($n eq 'POINT') { if($str_inits{$i}[1]) { my @c = &ano_cmd_par_op_point({ this => $str_inits{$i}[1] }); print STDOUT "\t" . "{ " . join(', ', split(/,/, $c[1])) . " }" . "\n"; } else { print STDOUT "\t" . "{ 0.0, 0.0, 0.0 }" . "\n"; } } print STDOUT "};" . "\n\n"; } # ...and the member types structure itself # print STDOUT "static struct dsl_member_types_t __UNUSED__ __" . $str_these{$on_struct} . "_t[" . @str_items . "] = {" . "\n"; # for(my $i = 0; $i < @str_items; $i++) { my $n = $str_names{$str_these{$on_struct}}{$str_items[$i]}; # my $v = $str_items[$i]; # If item name looks like 'item_name[2]', get rid of the tail # $v =~ s/\[.*$//; print STDOUT "\t" . "{ DSL_PARAM_TYPE_" . $n . ", "; print STDOUT "(void *) &__" . $str_these{$on_struct} . "_t_" . $i . " }"; if($i == (@str_items - 1)) { print STDOUT "\n"; } else { print STDOUT "," . "\n"; } } print STDOUT "};" . "\n\n"; # Print offsets to member types structure # if(@str_items) { print STDOUT "/* These are offsets to __" . $str_these{$on_struct} . "_t structure */" . "\n"; for(my $i = 0; $i < @str_items; $i++) { my $t = $str_items[$i]; # If item name looks like 'item_name[2]', get rid of the tail # $t =~ s/\[.*$//; print STDOUT "#define D_STRUCT_OFFSET_" . uc($str_these{$on_struct}) . "_" . uc($t) . " " . $i . "\n"; } print STDOUT "\n"; } # undef($str_names{$str_these{$on_struct}}); undef($str_types{$str_these{$on_struct}}); undef(%str_inits); undef(@str_items); $str_where = 0; $on_struct--; $var_loops -= $arg->{cmd} =~ tr/}$//; } # sub ano_cmd_call_debug { my ($arg) = @_; # Split command into pieces # my @c = split(/_/, $arg->{cmd}); my $f = "ano_cmd_call_debug_" . $c[0]; if(defined &$f) { &$f({ cmd => $arg->{cmd}, par => $arg->{par}, file => $arg->{file}, line => $arg->{line} }); } else { &msg_fail({ mess => "Unknown enabled block '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } sub ano_cmd_call_debug_debug { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if defined(PROG_HAS_DEBUG)", end => "#endif /* PROG_HAS_DEBUG */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debug_audio { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if ! defined(PROG_DISABLE_AUDIO)", end => "#endif /* ! PROG_DISABLE_AUDIO */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debug_bob { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if ! defined(PROG_DISABLE_GUI) && ! defined(PROG_DISABLE_BOB)", end => "#endif /* ! PROG_DISABLE_GUI && ! PROG_DISABLE_BOB */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debug_draw { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if ! defined(PROG_DISABLE_GUI) && ! defined(PROG_DISABLE_DRAW)", end => "#endif /* ! PROG_DISABLE_GUI && ! PROG_DISABLE_DRAW */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debug_gui { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if ! defined(PROG_DISABLE_GUI) && defined(PROG_HAS_X11)", end => "#endif /* ! PROG_DISABLE_GUI && PROG_HAS_X11 */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debug_input { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if ! defined(PROG_DISABLE_INPUT)", end => "#endif /* ! PROG_DISABLE_INPUT */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debug_menu { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if ! defined(PROG_DISABLE_GUI) && ! defined(PROG_DISABLE_MENU)", end => "#endif /* ! PROG_DISABLE_GUI && ! PROG_DISABLE_MENU */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debug_remote { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if ! defined(PROG_DISABLE_REMOTE)", end => "#endif /* ! PROG_DISABLE_REMOTE */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debug_widget { my ($arg) = @_; &ano_cmd_call_debugs_op({ cmd => $arg->{cmd}, par => $arg->{par}, now => "#if ! defined(PROG_DISABLE_GUI) && ! defined(PROG_DISABLE_WIDGET)", end => "#endif /* ! PROG_DISABLE_GUI && ! PROG_DISABLE_WIDGET */", file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_debugs_op { my ($arg) = @_; if($arg->{par} !~ /{$/) { &msg_fail({ mess => "Required '" . $arg->{cmd} . "' block opening token '{' is missing", line => $arg->{line} }); return; } $var_loops += $arg->{par} =~ tr/{$//; # Check if this statement has valid attributes # my $r; my ($n) = $arg->{par} =~ /\s*\[\s*(.*)\s*\]\s*/; if($n) { $r = &ano_cmd_call_debugs_at({ cmd => $arg->{cmd}, par => $n, file => $arg->{file}, line => $arg->{line} }); } # Comment possibly multilined statement out... # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); # ...and store C-preprocessor directive for later use to end this block # my @p = ( $arg->{end} ); $var_tails[$var_loops] = [ @p ]; # Print directive out to start wrapping command structures # my $p = $arg->{now}; if($r && $r ne "") { $p .= $r; } push @dsl_cmd_r, $p; print STDOUT $p . "\n"; } sub ano_cmd_call_debugs_at { my ($arg) = @_; my $r; if($arg->{par}) { my @p = split(/\s*,\s*/, $arg->{par}); foreach my $p (@p) { my ($e, $o) = split(/\s*[:=]\s*/, $p, 2); my $f = "ano_cmd_call_debugs_at_" . $arg->{cmd} . "_" . lc($e); if(defined &$f) { $o = lc($o) if($o); $r = &$f({ cmd => $e, opt => $o, file => $arg->{file}, line => $arg->{line} }); } else { &msg_fail({ mess => "Unknown attribute '" . $e . "' for statement '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } } return $r; } sub ano_cmd_call_debugs_at_debug_enabled_level { my ($arg) = @_; my $r; if($arg->{opt} =~ /^\d+$/) { $r = " && (PROG_HAS_DEBUG == " . $arg->{opt} . ")"; } else { &msg_fail({ mess => "Integer was expected with attribute '" . $arg->{cmd} . "', got '" . $arg->{opt} . "'", line => $arg->{line} }); return; } return $r; } # sub ano_cmd_call_ifjump { my ($arg) = @_; my %e = ( '==' => 'je', '!=' => 'jne', '<=' => 'jbe', '>=' => 'jae', '<' => 'jb', '>' => 'ja' ); my %f = ( '==' => 'jne', '!=' => 'je', '<=' => 'ja', '>=' => 'jb', '<' => 'jae', '>' => 'jbe' ); # Use capturing parentheses to return split delimiter as well # my @d = split(/(\s*==\s*|\s*!=\s*|\s*<=\s*|\s*>=\s*|\s*<\s*|\s*>\s*)/, $arg->{par}, 3); if(@d != 3) { &msg_fail({ mess => "Wrong number of statements in '" . $arg->{par} . "', got " . @d . ", expected 3", line => $arg->{line} }); return; } my @s = split(/\s*:\s*/, $d[2], 2); if(@s != 2) { &msg_fail({ mess => "Wrong number of statements in '" . $d[2] . "', got " . @s . ", expected 2", line => $arg->{line} }); return; } $d[1] =~ s/\s//go; if(!$e{$d[1]}) { &msg_fail({ mess => "Unknown condition operator '" . $d[1] . "'", line => $arg->{line} }); return; } if($s[0] !~ /^\(/) { $s[0] = '(' . $s[0]; } if($s[0] !~ /\)$/) { $s[0] = $s[0] . ')'; } # Insert instructions into source to test the condition... # my @p = (); if($s[1] =~ /^&/) { @p = ( "\t" . "cmp " . $d[0] . " " . $s[0] . "\n", "\t" . $f{$d[1]} . " " . "\"__if_" . $var_label . "_a\"" . "\n", "\t" . $s[1] . "\n", ": \"__if_" . $var_label . "_a\"" . "\n" ); # ...increase global statement counter for loop labels... # $var_label++; } else { if($s[1] !~ /^['"]/) { $s[1] = '"' . $s[1]; } if($s[1] !~ /['"]$/) { $s[1] = $s[1] . '"'; } @p = ( "\t" . "cmp " . $d[0] . " " . $s[0] . "\n", "\t" . $e{$d[1]} . " " . $s[1] . "\n" ); } splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); } # sub ano_cmd_call_tests { my ($arg) = @_; # Split command into pieces... # my $f = "ano_cmd_call_tests_"; my @c = split(/_/, $arg->{cmd}); # ...and figure out what it is # if($c[0] =~ /if/ || $c[0] =~ /unless/) { $f .= "if_or_unless"; } elsif($c[0] =~ /call/ || $c[0] =~ /ret/ || $c[0] =~ /end/ || $c[0] =~ /exit/) { $f .= shift(@c) . "_if_or_unless"; } if(defined &$f) { my $p; $p = $arg->{par} if($arg->{par}); &$f({ par => $p, jmp => $c[0], tst => $c[1], file => $arg->{file}, line => $arg->{line} }); } else { &msg_fail({ mess => "Unknown condition test '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } sub ano_cmd_call_tests_if_or_unless { my ($arg) = @_; my %t = ( 'if' => 'je', 'unless' => 'jne' ); if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter for condition test is missing", line => $arg->{line} }); return; } my @p = ( "\t" . "cmp rc (" . uc($arg->{tst}) . ")" . "\n", "\t" . $t{$arg->{jmp}} . " \"" . $arg->{par} . "\"" . "\n" ); # Insert instructions into source to test the condition... # splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment test keyword out # $arg->{file}[$arg->{line} - 1] =~ s/^/;/; } sub ano_cmd_call_tests_call_if_or_unless { my ($arg) = @_; my %t = ( 'if' => 'jne', 'unless' => 'je' ); if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter for condition test is missing", line => $arg->{line} }); return; } my @p = ( "\t" . "cmp rc (" . uc($arg->{tst}) . ")" . "\n", "\t" . $t{$arg->{jmp}} . " \"__tst_" . $var_tests . "\"" . "\n", "\t" . "call \"" . $arg->{par} . "\"" . "\n", ": \"__tst_" . $var_tests . "\"" . "\n" ); # Insert instructions into source to test the condition... # splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment test keyword out # $arg->{file}[$arg->{line} - 1] =~ s/^/;/; # Increase global statement counter for condition test labels # $var_tests++; } sub ano_cmd_call_tests_ret_if_or_unless { my ($arg) = @_; my %t = ( 'if' => 'jne', 'unless' => 'je' ); my $r = ""; $r = " " . $arg->{par} if($arg->{par}); my @p = ( "\t" . "cmp rc (" . uc($arg->{tst}) . ")" . "\n", "\t" . $t{$arg->{jmp}} . " \"__tst_" . $var_tests . "\"" . "\n", "\t" . "ret" . $r . "\n", ": \"__tst_" . $var_tests . "\"" . "\n" ); # Insert instructions into source to test the condition... # splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment test keyword out # $arg->{file}[$arg->{line} - 1] =~ s/^/;/; # Increase global statement counter for condition test labels # $var_tests++; } sub ano_cmd_call_tests_end_if_or_unless { my ($arg) = @_; my %t = ( 'if' => 'jne', 'unless' => 'je' ); my $r = ""; $r = " " . $arg->{par} if($arg->{par}); my @p = ( "\t" . "cmp rc (" . uc($arg->{tst}) . ")" . "\n", "\t" . $t{$arg->{jmp}} . " \"__tst_" . $var_tests . "\"" . "\n", "\t" . "end" . $r . "\n", ": \"__tst_" . $var_tests . "\"" . "\n" ); # Insert instructions into source to test the condition... # splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment test keyword out # $arg->{file}[$arg->{line} - 1] =~ s/^/;/; # Increase global statement counter for condition test labels # $var_tests++; } sub ano_cmd_call_tests_exit_if_or_unless { my ($arg) = @_; my %t = ( 'if' => 'jne', 'unless' => 'je' ); my $r = ""; $r = " " . $arg->{par} if($arg->{par}); my @p = ( "\t" . "cmp rc (" . uc($arg->{tst}) . ")" . "\n", "\t" . $t{$arg->{jmp}} . " \"__tst_" . $var_tests . "\"" . "\n", "\t" . "exit " . $r . "\n", ": \"__tst_" . $var_tests . "\"" . "\n" ); # Insert instructions into source to test the condition... # splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment test keyword out # $arg->{file}[$arg->{line} - 1] =~ s/^/;/; # Increase global statement counter for condition test labels # $var_tests++; } # sub ano_cmd_call_sc_call { my ($arg) = @_; # Fix the label name for function call # my $f = $arg->{cmd}; $f =~ s/^&/call /; $f =~ s/^call\s+/call "/; $f =~ s/$/"/; if($arg->{par} && $arg->{par} ne "") { if($arg->{par} !~ /^\(/) { $f .= " ("; } else { $f .= " "; } $f .= $arg->{par}; } # Insert function call into source... # my @p = ( "\t" . $f . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); } sub ano_cmd_call_sc_thread { my ($arg) = @_; # Fix the label name for thread spawn # my $f = $arg->{cmd}; $f =~ s/^@/thread_spawn /; $f =~ s/^thread_spawn\s+/thread_spawn ("/; $f =~ s/$/"/; if($arg->{par} && $arg->{par} ne "") { # Thread name was provided as a parameter # my $p = $arg->{par}; $p =~ s/^\s*\(\s*//; $p =~ s/\s*\).*$//; $f =~ s/\("/($p, "/; } else { # Thread name is same as the label # my ($p) = $f =~ /"(.*)"/; $f =~ s/\("/("$p", "/; } $f =~ s/$/)/; # Insert function call into source... # my @p = ( "\t" . $f . "\n" ); splice(@{ $arg->{file} }, $arg->{line}, 0, @p); # ...and comment possibly multilined statement out # &ano_cmd_call_loops_ec({ file => $arg->{file}, line => $arg->{line} }); } # sub ano_cmd_cmp { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my $c = $arg->{cnt}; my $d = $arg->{cmd}; my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); if(!$h || $h eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct source parameter # my @p = (); my $i = 1; $h =~ s/\)$//; my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $h, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, rpn => $r }); push @p, $t . ":n:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_STRING") { &ano_out_par_string({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_BLOB") { &ano_out_par_blob({ cmd => $d, val => $v, mod => $r, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":b:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINTER") { &ano_out_par_pointer({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":p:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_HANDLE") { &ano_out_par_handle({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":h:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_COLOR") { &ano_out_par_color({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":c:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_IMAGE") { &ano_out_par_image({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":m:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINT") { &ano_out_par_point({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":t:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { &ano_out_par_variable({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible source parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct destination parameter # ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $g, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_VARIABLE") { my ($e, $f, $u, $w) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . ", &dsl_cmd_" . $d . "_param_" . $f . "_" . $u . "_" . $w . "," . "\n"; print STDOUT "\t" . "NULL, NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible destination parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } sub ano_cmd_dec { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_div { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_end { my ($arg) = @_; my $c = $arg->{cnt}; my $d = $arg->{cmd}; if($arg->{par} && $arg->{par} ne "") { my @p = (); my $i = 1; my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $arg->{par}, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i, rpn => $r }); push @p, $t . ":n:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $d . "_v dsl_cmd_" . $d . "_v_" . $c . "_" . $i . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "\t" . ", NULL" . "\n"; print STDOUT "};" . "\n\n"; push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my ($e, $f, $g, $h) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . ", &dsl_cmd_" . $d . "_" . $f . "_" . $g . "_" . $h . "\n"; print STDOUT "};" . "\n\n"; } else { print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . "DSL_PARAM_TYPE_NONE, NULL" . "\n"; print STDOUT "};" . "\n\n"; } } sub ano_cmd_inc { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ja { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jae { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jb { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jbe { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_je { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jne { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_js { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jns { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jz { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jnz { my ($arg) = @_; &ano_cmd_jmp({ cmd => "jmp", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jmp { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my $c = $arg->{cnt}; my $d = $arg->{cmd}; my $p = $arg->{par}; # Try to guess destination label type # if($p =~ /^['"](.*)['"]$/) { # This is quoted string... # } elsif($p =~ /^[\w]+$/i) { # ...this is non-quoted... # $p = '"' . $p; $p = $p . '"'; } elsif($p =~ /^\[\s*var\s*\]\s*[\w]+$/i) { # ...and this is meant to be a variable # $p =~ s/^\[[\w]+\]\s*//i; } else { &msg_fail({ mess => "Parameter format is unknown for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $p, line => $arg->{line} }); # Remove possible casting and quotes at this point # $v =~ s/^.*?['"]//; $v =~ s/['"]\s*$//; my @p = (); my $i = 1; if($t eq "DSL_PARAM_TYPE_STRING") { &ano_out_par_string({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $d . "_v dsl_cmd_" . $d . "_v_" . $c . "_" . $i . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "\t" . ", NULL" . "\n"; print STDOUT "};" . "\n\n"; push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my ($e, $f, $g, $h) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . "," . "\n"; print STDOUT "\t" . "0," . "\n"; print STDOUT "\t" . "&dsl_cmd_" . $d . "_" . $f . "_" . $g . "_" . $h . "\n"; print STDOUT "};" . "\n\n"; } sub ano_cmd_label { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for label '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my $c = $arg->{cnt}; my $d = $arg->{cmd}; my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); # Store label name to be used with variable aliasing # $var_where = $g; $var_these{$var_where} = [ ]; # Construct expected parameters for this label # my @p = (); my $i = 1; if($h && $h ne "") { $h =~ s/\s*\)\s*$//; # Split label parameters by comma # foreach my $p (split(/\s*,\s*/, $h)) { my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $p, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_VARIABLE") { &ano_out_par_variable({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . " @ " . $v . "' for label", line => $arg->{line} }); return; } $i++; } print STDOUT "static struct dsl_cmd_" . $d . "_param dsl_cmd_" . $d . "_q_" . $c . "[" . $i . "] = {" . "\n"; foreach my $p (@p) { my ($e, $f, $g, $h) = split(/:/, $p); print STDOUT "\t" . "{ " . $e . ", &dsl_cmd_" . $d . "_param_" . $f . "_" . $g . "_" . $h . " }," . "\n"; } print STDOUT "\t" . "{ DSL_PARAM_TYPE_NONE, NULL }" . "\n"; print STDOUT "};" . "\n\n"; } # Construct label name # @p = (); my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $g, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_STRING") { # Remove possible casting and quotes at this point # $v =~ s/^.*?['"]//; $v =~ s/['"]\s*$//; &ano_out_par_string({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . " @ " . $v . "' for label", line => $arg->{line} }); return; } # Check label parameters against possible prototype # if($v !~ /^__/ && &alt_flags_check({ flag => 'USE_PROTOS' })) { &ano_cmd_call_op({ what => $v, this => \{}, slot => $i, only => 1, line => $arg->{line} }); } # my ($e, $f, $u, $w) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . "," . "\n"; print STDOUT "\t" . "0, 0," . "\n"; print STDOUT "\t" . "&dsl_cmd_" . $d . "_" . $f . "_" . $u . "_" . $w . "," . "\n"; if($h && $h ne "") { print STDOUT "\t" . "dsl_cmd_" . $d . "_q_" . $c . "\n"; } else { print STDOUT "\t" . "NULL" . "\n"; } print STDOUT "};" . "\n\n"; } sub ano_cmd_mod { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_mov { my ($arg) = @_; &ano_cmd_mov_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_deliver { my ($arg) = @_; &ano_cmd_mov_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_fetch { my ($arg) = @_; &ano_cmd_mov_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_mov_op { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my $c = $arg->{cnt}; my $d = $arg->{cmd}; my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); if(!$h || $h eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct parameter to move # my @p = (); my $i = 1; $h =~ s/\)$//; my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $h, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, rpn => $r }); push @p, $t . ":n:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_STRING") { # Remove possible casting and quotes at this point # $v =~ s/^.*?['"]//; $v =~ s/['"]\s*$//; &ano_out_par_string({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_BLOB") { &ano_out_par_blob({ cmd => $d, val => $v, mod => $r, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":b:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINTER") { &ano_out_par_pointer({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":p:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_HANDLE") { &ano_out_par_handle({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":h:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_COLOR") { &ano_out_par_color({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":c:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_IMAGE") { &ano_out_par_image({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":m:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINT") { &ano_out_par_point({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":t:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { &ano_out_par_variable({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible source parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct parameter where to move to # ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $g, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_BLOB") { my ($e, $f, $u, $w) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . ", &dsl_cmd_" . $d . "_param_" . $f . "_" . $u . "_" . $w . "," . "\n"; print STDOUT "\t" . "NULL, NULL," . "\n"; # Blob member mapping variable is named as structure.member # $d = $r; $c = "D_STRUCT_OFFSET_" . uc($v). "_"; $d =~ s/^$c//; &ano_out_par_variable_op({ val => $v . "." . lc($d), mod => "BLOB", mbr => $r, blt => $r, bls => "(struct dsl_member_types_t *) __" . $v . "_t" }); print STDOUT "};" . "\n\n"; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { my ($e, $f, $u, $w) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . ", &dsl_cmd_" . $d . "_param_" . $f . "_" . $u . "_" . $w . "," . "\n"; print STDOUT "\t" . "NULL, NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible destination parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } sub ano_cmd_mul { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_neg { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_not { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_pow { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_rand { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ret { my ($arg) = @_; my $c = $arg->{cnt}; my $d = $arg->{cmd}; if($arg->{par} && $arg->{par} ne "") { my @p = (); my $i = 1; my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $arg->{par}, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i, rpn => $r }); push @p, $t . ":n:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_STRING") { &ano_out_par_string({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_BLOB") { &ano_out_par_blob({ cmd => $d, val => $v, mod => $r, cnt => $c, i => $i }); push @p, $t . ":b:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINTER") { &ano_out_par_pointer({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i }); push @p, $t . ":p:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_HANDLE") { &ano_out_par_handle({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i }); push @p, $t . ":h:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_COLOR") { &ano_out_par_color({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i, mbr => $r }); push @p, $t . ":c:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_IMAGE") { &ano_out_par_image({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i, mbr => $r }); push @p, $t . ":m:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINT") { &ano_out_par_point({ cmd => $d, val => $v, mod => $m, cnt => $c, i => $i, mbr => $r }); push @p, $t . ":t:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $d . "_v dsl_cmd_" . $d . "_v_" . $c . "_" . $i . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "\t" . ", NULL" . "\n"; print STDOUT "};" . "\n\n"; push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my ($e, $f, $g, $h) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . ", &dsl_cmd_" . $d . "_" . $f . "_" . $g . "_" . $h . "," . "\n"; print STDOUT "\t" . "NULL" . "\n"; print STDOUT "};" . "\n\n"; } else { print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . "DSL_PARAM_TYPE_NONE, NULL," . "\n"; print STDOUT "\t" . "NULL" . "\n"; print STDOUT "};" . "\n\n"; } } sub ano_cmd_sub { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_var { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my $c = $arg->{cnt}; my $d = $arg->{cmd}; my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $arg->{par}, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, ntp => $m, mod => "NUMBER", mbr => "DSL_MEMBER_TYPE_NONE" }); print STDOUT "};" . "\n\n"; } elsif($t eq "DSL_PARAM_TYPE_STRING") { print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, chr => $m, mod => "STRING", mbr => "DSL_MEMBER_TYPE_NONE" }); print STDOUT "};" . "\n\n"; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } # sub ano_cmd_clall { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_cla { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_clb { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_cle { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_cls { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_clz { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_stall { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_sta { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_stb { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ste { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_sts { my ($arg) = @_; &ano_cmd_stz({ cmd => "flag", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_stz { my ($arg) = @_; my $c = $arg->{cnt}; my $d = $arg->{cmd}; print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "};" . "\n\n"; } # sub ano_cmd_and { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_or { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_xor { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_test { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } # sub ano_cmd_isfinite { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_isinf { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_isnan { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_isnormal { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_signbit { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_nan { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ceil { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_floor { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_nearbyint { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_rint { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_round { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_trunc { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_sqrt { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_cbrt { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_exp { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_exp2 { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_expm1 { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_log { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_log2 { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_log10 { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_log1p { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_logb { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ilogb { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_cos { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_cosh { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_acos { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_acosh { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_sin { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_sinh { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_asin { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_asinh { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tan { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tanh { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_atan { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_atanh { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tgamma { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_lgamma { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_j0 { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_j1 { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_y0 { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_y1 { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_erf { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_erfc { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_gdens { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_gdist { my ($arg) = @_; &ano_cmd_arith_two_op({ cmd => "math2", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_copysign { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_nextafter { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_nexttoward { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_remainder { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_dim { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_max { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_min { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_hypot { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_modf { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_frexp { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ldexp { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_scalbn { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_atan2 { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_jn { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_yn { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_grand { my ($arg) = @_; &ano_cmd_arith_three_op({ cmd => "math3", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_fma { my ($arg) = @_; &ano_cmd_arith_four_op({ cmd => "math4", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } # sub ano_cmd_crc32 { my ($arg) = @_; &ano_cmd_crc_op({ cmd => "crc32", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_crc64 { my ($arg) = @_; &ano_cmd_crc_op({ cmd => "crc64", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_crc_op { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my $c = $arg->{cnt}; my $d = $arg->{cmd}; my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); if(!$h || $h eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct source parameter # my @p = (); my $i = 1; $h =~ s/\)$//; my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $h, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, rpn => $r }); push @p, $t . ":n:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_STRING") { &ano_out_par_string({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":s:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_BLOB") { &ano_out_par_blob({ cmd => $d, val => $v, mod => $r, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":b:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINTER") { &ano_out_par_pointer({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":p:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_HANDLE") { &ano_out_par_handle({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i }); push @p, $t . ":h:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_COLOR") { &ano_out_par_color({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":c:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_IMAGE") { &ano_out_par_image({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":m:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_POINT") { &ano_out_par_point({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":t:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { &ano_out_par_variable({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible source parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct destination parameter # ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $g, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_VARIABLE") { my ($e, $f, $u, $w) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; print STDOUT "\t" . $e . ", &dsl_cmd_" . $d . "_param_" . $f . "_" . $u . "_" . $w . "," . "\n"; print STDOUT "\t" . "NULL, NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible destination parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } # sub ano_cmd_dump { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_print { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $arg->{par}, line => $arg->{line} }); # Convert everything to be printed to strings # undef($r) if($r); $t = 'DSL_PARAM_TYPE_STRING'; if($m !~ /^CHARSET_/ && $m !~ /^UTF-/) { $m = 'CHARSET_DEFAULT'; } # If there is variable which has letters, numbers and maybe underscore... # my $k = ""; if($v =~ /^[a-zA-Z0-9_]+\s*\(/ && $v =~ /\)$/) { # ...this includes destination variable name # $v =~ s/\)$//; ($k, $v) = split(/\s*\(/, $v, 2); } if($t eq "DSL_PARAM_TYPE_NUMBER") { print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; print STDOUT "\t" . "NULL," . "\n"; &ano_out_par_variable_op({ val => "", mod => "NUMBER", mbr => "DSL_MEMBER_TYPE_NONE", num => $v, end => "," }); &ano_out_par_variable_op({ val => $k, mod => "NONE", mbr => "DSL_MEMBER_TYPE_NONE" }); print STDOUT "};" . "\n\n"; } elsif($t eq "DSL_PARAM_TYPE_STRING") { print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; print STDOUT "\t" . "NULL," . "\n"; &ano_out_par_variable_op({ val => "", mod => "STRING", mbr => "DSL_MEMBER_TYPE_NONE", str => $v, end => "," }); &ano_out_par_variable_op({ val => $k, mod => "NONE", mbr => "DSL_MEMBER_TYPE_NONE" }); print STDOUT "};" . "\n\n"; } elsif($t eq "DSL_PARAM_TYPE_BLOB") { print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; print STDOUT "\t" . "NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => "BLOB", mbr => "DSL_MEMBER_TYPE_NONE", blt => $r, bls => "(struct dsl_member_types_t *) __" . $v . "_t", end => "," }); &ano_out_par_variable_op({ val => $k, mod => "NONE", mbr => "DSL_MEMBER_TYPE_NONE" }); print STDOUT "};" . "\n\n"; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; print STDOUT "\t" . "NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r, end => "," }); &ano_out_par_variable_op({ val => $k, mod => "NONE", mbr => "DSL_MEMBER_TYPE_NONE" }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } # sub ano_cmd_ston { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "conv", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_pton { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "conv", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_hton { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "conv", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ntos { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "conv", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ntop { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "conv", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_ntoh { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "conv", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toi8 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toi16 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toi32 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toi64 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toi128 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toisize { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tou8 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tou16 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tou32 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tou64 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tou128 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tousize { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tof32 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tof64 { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tochar { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toshort { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toint { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tolong { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_touchar { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toushort { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_touint { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_toulong { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_tofloat { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_todouble { my ($arg) = @_; &ano_cmd_arith_one_op({ cmd => "type", par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } # sub ano_cmd_enter { my ($arg) = @_; &ano_cmd_arith_one_on({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } sub ano_cmd_leave { my ($arg) = @_; &ano_cmd_arith_one_on({ cmd => $arg->{cmd}, par => $arg->{par}, cnt => $arg->{cnt}, line => $arg->{line} }); } # sub ano_cmd_arith_one_on { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct parameter # my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $arg->{par}, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; print STDOUT "\t" . "{ " . $m . "," . "\n"; if($r && $r ne "") { # Squeeze rpn string, these should go hand in hand with engine/dsl_rpn.c... # $v =~ s/[\a\b\s\v\f\e]+//g; # ...and optimize rpn variable names if needed # if(&alt_flags_check({ flag => 'VAR_NAME_SUBS' })) { $v = &ano_out_par_number_op({ rpn => $v }); } print STDOUT "\t" . " { 0.0 }," . "\n"; print STDOUT "\t" . " { { { (\"" . &ano_out_hex_bytes({ str => $v }) . "\"), " . &ano_out_len_bytes({ str => $v }) . ", 0 }," . "\n"; print STDOUT "\t" . " { CHARSET_DEFAULT, CHARSET_DEFAULT_SIZE, 0 } }," . "\n"; } else { print STDOUT "\t" . " { " . $v . " }," . "\n"; print STDOUT "\t" . " { { { NULL, 0, 0 }, { NULL, 0, 0 } }," . "\n"; } print STDOUT "\t" . " IS_NO, 0.0 }" . "\n"; print STDOUT "\t" . "}" . "\n"; print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } sub ano_cmd_arith_one_op { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $arg->{par}, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_BLOB") { print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; print STDOUT "\t" . "NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => "BLOB", mbr => "DSL_MEMBER_TYPE_NONE", blt => $r, bls => "(struct dsl_member_types_t *) __" . $v . "_t" }); print STDOUT "};" . "\n\n"; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; print STDOUT "\t" . "NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } sub ano_cmd_arith_two_op { my ($arg) = @_; my @p = (); my $i = 1; my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } $h =~ s/\)$//; if(!$h || $h eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct source parameter # my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $h, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $arg->{cmd}, val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $i, rpn => $r }); push @p, $t . ":n:" . $arg->{cnt} . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { &ano_out_par_variable({ cmd => $arg->{cmd}, val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":v:" . $arg->{cnt} . ":" . $i; } else { &msg_fail({ mess => "Incompatible source parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct destination parameter # ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $g, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_VARIABLE") { my ($e, $f, $u, $w) = split(/:/, $p[0]); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; print STDOUT "\t" . $e . ", &dsl_cmd_" . $arg->{cmd} . "_param_" . $f . "_" . $u . "_" . $w . "," . "\n"; print STDOUT "\t" . "NULL, NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible destination parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } sub ano_cmd_arith_three_op { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); my ($o) = $arg->{par} =~ /\((.*)\)/; my @o = split(/,/, $o); unshift @o, $g if(@o == 1); if(@o != 2) { &msg_fail({ mess => "Wrong number of arguments for '" . $arg->{cmd} . "', got " . @o . ", expected 2", line => $arg->{line} }); return; } # Construct source parameters # my @p = (); my $i = 1; foreach my $p (@o) { my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $p, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $arg->{cmd}, val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $i, rpn => $r }); push @p, $t . ":n:" . $arg->{cnt} . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { &ano_out_par_variable({ cmd => $arg->{cmd}, val => $v, mod => $m, cnt => $arg->{cnt}, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":v:" . $arg->{cnt} . ":" . $i; } else { &msg_fail({ mess => "Incompatible source parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } $i++; } # Construct destination parameter # ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $g, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . " dsl_cmd_" . $arg->{cnt} . " = {" . "\n"; foreach my $p (@p) { my ($e, $f, $u, $w) = split(/:/, $p); print STDOUT "\t" . $e . ", &dsl_cmd_" . $arg->{cmd} . "_param_" . $f . "_" . $u . "_" . $w . "," . "\n"; } print STDOUT "\t" . "NULL, NULL, NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible destination parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } sub ano_cmd_arith_four_op { my ($arg) = @_; if(!$arg->{par} || $arg->{par} eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } my $c = $arg->{cnt}; my $d = $arg->{cmd}; my ($g, $h) = split(/\s*\(\s*/, $arg->{par}, 2); if(!$h || $h eq "") { &msg_fail({ mess => "Required parameter is missing for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } # Construct source parameters # $h =~ s/\)$//; my @o = split(/,/, $h); my @p = (); my $i = 1; if(@o != 3) { &msg_fail({ mess => "Wrong number of arguments for '" . $arg->{cmd} . "', got " . @o . ", expected 3", line => $arg->{line} }); return; } foreach my $p (@o) { my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $p, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_NUMBER") { &ano_out_par_number({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, rpn => $r }); push @p, $t . ":n:" . $c . ":" . $i; } elsif($t eq "DSL_PARAM_TYPE_VARIABLE") { &ano_out_par_variable({ cmd => $d, val => $v, mod => $m, cnt => $c, pad => "_param", i => $i, mbr => $r }); push @p, $t . ":v:" . $c . ":" . $i; } else { &msg_fail({ mess => "Incompatible source parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } $i++; } # Construct destination parameter # my ($t, $v, $m, $r) = &ano_cmd_par_op({ par => $g, line => $arg->{line} }); if($t eq "DSL_PARAM_TYPE_VARIABLE") { print STDOUT "static struct dsl_cmd_" . $d . " dsl_cmd_" . $c . " = {" . "\n"; foreach my $p (@p) { my ($e, $f, $u, $w) = split(/:/, $p); print STDOUT "\t" . $e . ", &dsl_cmd_" . $d . "_param_" . $f . "_" . $u . "_" . $w . "," . "\n"; } print STDOUT "\t" . "NULL, NULL, NULL, NULL," . "\n"; &ano_out_par_variable_op({ val => $v, mod => $m, mbr => $r }); print STDOUT "};" . "\n\n"; } else { &msg_fail({ mess => "Incompatible destination parameter type '" . $t . "' for '" . $arg->{cmd} . "'", line => $arg->{line} }); return; } } # sub ano_cmd_par_op { my ($arg) = @_; my %s = ( 'utf8', => 'UTF-8', 'utf-8', => 'UTF-8', 'utf32', => 'UTF-32', 'utf-32', => 'UTF-32', 'utf32be', => 'UTF-32BE', 'utf-32be', => 'UTF-32BE', 'utf32le', => 'UTF-32LE', 'utf-32le', => 'UTF-32LE', 'default' => 'CHARSET_DEFAULT' ); my %n = ( # Internal representations... # 'int8' => 'DSL_NUMBER_TYPE_I8', 'int16' => 'DSL_NUMBER_TYPE_I16', 'int32' => 'DSL_NUMBER_TYPE_I32', 'int64' => 'DSL_NUMBER_TYPE_I64', 'int128' => 'DSL_NUMBER_TYPE_I128', 'uint8' => 'DSL_NUMBER_TYPE_U8', 'uint16' => 'DSL_NUMBER_TYPE_U16', 'uint32' => 'DSL_NUMBER_TYPE_U32', 'uint64' => 'DSL_NUMBER_TYPE_U64', 'uint128' => 'DSL_NUMBER_TYPE_U128', 'char' => 'DSL_NUMBER_TYPE_CHAR', 'short' => 'DSL_NUMBER_TYPE_SHORT', 'int' => 'DSL_NUMBER_TYPE_INT', 'long' => 'DSL_NUMBER_TYPE_LONG', 'uchar' => 'DSL_NUMBER_TYPE_UCHAR', 'ushort' => 'DSL_NUMBER_TYPE_USHORT', 'uint' => 'DSL_NUMBER_TYPE_UINT', 'ulong' => 'DSL_NUMBER_TYPE_ULONG', 'float' => 'DSL_NUMBER_TYPE_FLOAT', 'double' => 'DSL_NUMBER_TYPE_DOUBLE', # ...and the ones that should be used # 'i8' => 'DSL_NUMBER_TYPE_I8', 'i16' => 'DSL_NUMBER_TYPE_I16', 'i32' => 'DSL_NUMBER_TYPE_I32', 'i64' => 'DSL_NUMBER_TYPE_I64', 'i128' => 'DSL_NUMBER_TYPE_I128', 'isize' => 'DSL_NUMBER_TYPE_ISIZE', 'u8' => 'DSL_NUMBER_TYPE_U8', 'u16' => 'DSL_NUMBER_TYPE_U16', 'u32' => 'DSL_NUMBER_TYPE_U32', 'u64' => 'DSL_NUMBER_TYPE_U64', 'u128' => 'DSL_NUMBER_TYPE_U128', 'usize' => 'DSL_NUMBER_TYPE_USIZE', 'f32' => 'DSL_NUMBER_TYPE_FLOAT', 'f64' => 'DSL_NUMBER_TYPE_DOUBLE', 'byte' => 'DSL_NUMBER_TYPE_U8', 'dec' => 'DSL_NUMBER_TYPE_DEFAULT', 'hex' => 'DSL_NUMBER_TYPE_DEFAULT', 'oct' => 'DSL_NUMBER_TYPE_DEFAULT', 'bin' => 'DSL_NUMBER_TYPE_DEFAULT', 'rpn' => 'DSL_NUMBER_TYPE_DEFAULT', 'default' => 'DSL_NUMBER_TYPE_DEFAULT' ); my %m = ( 'number' => 'NUMBER', 'string' => 'STRING', 'blob' => 'BLOB', 'struct' => 'BLOB', 'pointer' => 'POINTER', 'handle' => 'HANDLE', 'color' => 'COLOR', 'image' => 'IMAGE', 'point' => 'POINT', 'default' => 'NONE' ); my $c = 'default'; my $d = 0; my $p = $arg->{par}; $p =~ s/^\s+|\s+$//; # If param starts with [, it is probably a cast # if($p =~ /^\[\s*[\w-]+\s*\]/i) { # Check if this is a variable type cast # while(my ($k, $v) = each %m) { if($p =~ /^\[\s*$k?\s*\]/) { $d = 1; last; } } # Check if this is a string type cast # if($d == 0) { while(my ($k, $v) = each %s) { if($p =~ /^\[\s*$k?\s*\]/) { $d = 2; last; } } } # Check if this is a number type cast # if($d == 0) { while(my ($k, $v) = each %n) { if($p =~ /^\[\s*$k?\s*\]/) { $d = 3; last; } } } my $q = $p; $q =~ s/^\[\s*//; $q =~ s/\s*\].*$//; # Get the cast, otherwise it was unrecognized # if($d != 0) { $p =~ s/^\[\s*[\w-]+\s*\]\s*//i; } else { &msg_fail({ mess => "Type cast '" . $q . "' is unknown", line => $arg->{line} }); return; } $c = $q; } # If parameter is empty, it is empty # if($p eq "") { if($d == 2) { return('DSL_PARAM_TYPE_STRING', '', ''); } elsif($d == 3) { return('DSL_PARAM_TYPE_NUMBER', '', ''); } return('DSL_PARAM_TYPE_NONE', '', ''); } # If parameter type is set, trust that... # if($d == 2) { $c = &ano_cmd_par_op_string({ hash => \%s, cast => $c }); return('DSL_PARAM_TYPE_STRING', $p, $c); } elsif($d == 3) { $p = ano_cmd_par_op_number_op({ this => $p, cast => $c, line => $arg->{line} }); $c = ano_cmd_par_op_number({ hash => \%n, cast => $c }); if($p =~ /^rpn:/) { # Return different list if this is an rpn expression # $p =~ s/^rpn://; return('DSL_PARAM_TYPE_NUMBER', $p, $c, 'rpn'); } if($p =~ /^([+-])?[0-9._]+([eE][0-9]+)?$/) { # This had a cast, so this seems like an ordinary number after all # return('DSL_PARAM_TYPE_NUMBER', $p, $c); } # This does not seem to be an ordinary number, so it is rpn expression then # return('DSL_PARAM_TYPE_NUMBER', $p, $c, 'rpn'); } # ...but if it is not set, start guessing what type the parameter may be # if($p eq 'NULL') { # NULL is empty string for sure # return('DSL_PARAM_TYPE_STRING', '', 'CHARSET_DEFAULT'); } elsif($p =~ /^['"](.*)['"]$/) { # Try to nick something between quotes, and if ok, this is probably a string # $c = &ano_cmd_par_op_string({ hash => \%s, cast => $c }); return('DSL_PARAM_TYPE_STRING', $p, $c); } elsif($p =~ /^\$/) { # Blob # $p =~ s/^\$\s*//; return('DSL_PARAM_TYPE_BLOB', $p, ''); } elsif($p =~ /^\*/) { # Pointer # $p =~ s/^\*\s*//; return('DSL_PARAM_TYPE_POINTER', $p, ''); } elsif($p =~ /^@/) { # Handle # $p =~ s/^@\s*//; return('DSL_PARAM_TYPE_HANDLE', $p, ''); } elsif($p =~ /^#/) { # Color # return &ano_cmd_par_op_color({ this => $p }); } elsif($p =~ /^%/) { # Image # $p =~ s/^%\s*['"]//; $p =~ s/['"]\s*$//; return('DSL_PARAM_TYPE_IMAGE', $p, ''); } elsif($p =~ /^&/) { # Point # return &ano_cmd_par_op_point({ this => $p }); } elsif($p =~ /^0b[0-1_]+$/i || $p =~ /^0o[0-7_]+$/i || $p =~ /^0x[0-9a-f_]+$/i || $p =~ /^b['"](.*)['"]$/i || $p =~ /^([+-])?[0-9._]+([eE][0-9]+)?$/) { # Number starts with 0b, 0o, 0x, integer, or with plus or minus sign # if($p =~ /^0b[0-1_]+$/i) { $p = ano_cmd_par_op_number_op({ this => $p, cast => 'bin', line => $arg->{line} }); } elsif($p =~ /^0o[0-7_]+$/i) { $p = ano_cmd_par_op_number_op({ this => $p, cast => 'oct', line => $arg->{line} }); } elsif($p =~ /^0x[0-9a-f_]+$/i) { $p = ano_cmd_par_op_number_op({ this => $p, cast => 'hex', line => $arg->{line} }); } elsif($p =~ /^b['"](.*)['"]$/i) { $p = ano_cmd_par_op_number_op({ this => $p, cast => 'byte', line => $arg->{line} }); $c = 'uint8'; } else { $p = ano_cmd_par_op_number_op({ this => $p, cast => 'dec', line => $arg->{line} }); } $c = ano_cmd_par_op_number({ hash => \%n, cast => $c }); return('DSL_PARAM_TYPE_NUMBER', $p, $c); } elsif($p =~ /^[a-z0-9_]+$/i) { # Variable or defined macro has letters, numbers and maybe underscore # if(defined($var_const{$p})) { # This is defined macro # $p = $var_const{$p}; if($p eq 'ZERO') { $p = 0; } return &ano_cmd_par_op({ par => $p, line => $arg->{line} }); } $c = 'number' if($c ne 'default' && $n{$c}); return('DSL_PARAM_TYPE_VARIABLE', $p, $m{$c}, 'DSL_MEMBER_TYPE_NONE'); } elsif($p =~ /^[a-z0-9_]+\.[a-z0-9_]+$/i) { # Variable name with member has letters, numbers, possibly underscore # and a dot somewhere in between # my $q = $p; $p =~ s/\..*$//; $q =~ s/^.*?\.//; $c = 'number' if($c ne 'default' && $n{$c}); if($str_store{$p}) { # This is member of already defined structure... # return('DSL_PARAM_TYPE_BLOB', $p, $m{$c}, 'D_STRUCT_OFFSET_' . uc($p) . '_' . uc($q)); } else { # ...and this is variable member # return('DSL_PARAM_TYPE_VARIABLE', $p, $m{$c}, 'DSL_MEMBER_TYPE_' . uc($q)); } } # If nothing from above matches, this string is most likely an rpn expression # return('DSL_PARAM_TYPE_NUMBER', $p, $n{$c}, 'rpn'); } sub ano_cmd_par_op_number { my ($arg) = @_; my %s = %{ $arg->{hash} }; unless($s{$arg->{cast}}) { &msg_fail({ mess => "Unknown number type '" . $arg->{cast} . "'", line => $arg->{line} }); return; } return $s{$arg->{cast}}; } sub ano_cmd_par_op_number_op { my ($arg) = @_; my $r = $arg->{this}; if($arg->{cast} =~ /^byte/i || $r =~ /^b['"](.*)['"]$/i) { # Handle single byte # if($r =~ /^.*?['"]/ && $r =~ /['"]$/) { $r =~ s/^.*?['"]//; $r =~ s/['"]$//; if(length($r) != 1) { &msg_fail({ mess => "Byte '" . $arg->{this} . "' length must be exactly one character", line => $arg->{line} }); return; } $r = ord($r); } if($r !~ /^\d+$/) { &msg_fail({ mess => "Invalid value '" . $arg->{this} . "' for byte", line => $arg->{line} }); return; } } elsif($arg->{cast} =~ /^dec/i || $r =~ /^([+-])?[0-9.]+([eE][0-9]+)?$/) { $r =~ s/_//g; if($r !~ /^([+-])?[0-9.]+([eE][0-9]+)?$/) { &msg_fail({ mess => "Invalid decimal number '" . $r . "'", line => $arg->{line} }); return; } # Decimal does not need any special whipping # } elsif($arg->{cast} =~ /^hex/i || $r =~ /^0x[0-9a-f]+$/i) { $r =~ s/_//g; if($r !~ /^0x[0-9a-f]+$/i) { &msg_fail({ mess => "Invalid hex number '" . $r . "'", line => $arg->{line} }); return; } $r = hex($r); } elsif($arg->{cast} =~ /^oct/i || $r =~ /^0o[0-7]+$/i) { $r =~ s/_//g; if($r !~ /^0o[0-7]+$/i) { &msg_fail({ mess => "Invalid octal number '" . $r . "'", line => $arg->{line} }); return; } $r = oct($r); } elsif($arg->{cast} =~ /^bin/i || $r =~ /^0b[0-1]+$/i) { $r =~ s/_//g; if($r !~ /^0b[0-1]+$/i) { &msg_fail({ mess => "Invalid binary number '" . $r . "'", line => $arg->{line} }); return; } $r = oct($r); } elsif($arg->{cast} =~ /^rpn/i) { # Ugly way to tell the caller that this is an rpn expression # $r = 'rpn:' . $r; } return $r; } sub ano_cmd_par_op_string { my ($arg) = @_; my %s = %{ $arg->{hash} }; unless($s{$arg->{cast}}) { &msg_fail({ mess => "Unknown string type '" . $arg->{cast} . "'", line => $arg->{line} }); return; } if($arg->{cast} eq 'default' && $alt_flags{'@ANO_FLAGS_DEFAULT_CHARSET'} ne '') { return $alt_flags{'@ANO_FLAGS_DEFAULT_CHARSET'}; } return $s{$arg->{cast}}; } sub ano_cmd_par_op_color { my ($arg) = @_; my $p = $arg->{this}; $p =~ s/^#\s*//; my @c = split(/\s*,\s*/, $p); if(@c == 1) { @c = ($c[0], $c[0], $c[0], '255'); } elsif(@c == 2) { @c = ($c[0], $c[0], $c[0], $c[1]); } elsif(@c == 3) { @c = ($c[0], $c[1], $c[2], '255'); } elsif(@c != 4) { &msg_fail({ mess => "Unknown color definition '" . $p . "'", line => $arg->{line} }); return; } return('DSL_PARAM_TYPE_COLOR', join(',', @c), ''); } sub ano_cmd_par_op_point { my ($arg) = @_; my $p = $arg->{this}; $p =~ s/^&\s*//; my @c = split(/\s*,\s*/, $p); if(@c == 1) { @c = ($c[0], '0.0', '0.0'); } elsif(@c == 2) { @c = ($c[0], $c[1], '0.0'); } elsif(@c != 3) { &msg_fail({ mess => "Unknown point definition '" . $p . "'", line => $arg->{line} }); return; } return('DSL_PARAM_TYPE_POINT', join(',', @c), ''); } sub ano_out_par_number { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad}); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_n dsl_cmd_" . $arg->{cmd} . $p . "_n_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; print STDOUT "\t" . "{ " . $arg->{mod} . "," . "\n"; if($arg->{rpn} && $arg->{rpn} ne "") { my $r = $arg->{val}; # Optimize rpn variable names if needed # if(&alt_flags_check({ flag => 'VAR_NAME_SUBS' })) { $r = &ano_out_par_number_op({ rpn => $r }); } else { $r = &ano_out_par_number_op({ rpn => $r, not => 1 }); } print STDOUT "\t" . " { 0.0 }," . "\n"; print STDOUT "\t" . " { { { (\"" . &ano_out_hex_bytes({ str => $r }) . "\"), " . &ano_out_len_bytes({ str => $r }) . ", 0 }," . "\n"; print STDOUT "\t" . " { CHARSET_DEFAULT, CHARSET_DEFAULT_SIZE, 0 } }," . "\n"; } else { my $r = $arg->{val}; # This should not return rpn expression anymore # if(defined($var_const{$r})) { $r = $var_const{$r}; if($r eq 'ZERO') { $r = 0; } } $r = &ano_cmd_par_op_number_op({ this => $r, cast => 'guess' }); print STDOUT "\t" . " { " . $r . " }," . "\n"; print STDOUT "\t" . " { { { NULL, 0, 0 }, { NULL, 0, 0 } }," . "\n"; } print STDOUT "\t" . " IS_NO, 0.0 }" . "\n"; print STDOUT "\t" . "}" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_out_par_number_op { my ($arg) = @_; my @r = (); my $r = $arg->{rpn}; # Squeeze rpn string, these should go hand in hand with engine/dsl_rpn.c # $r =~ s/[\a\b\s\v\f\e]+//g; # Delimiters should go hand in hand with engine/dsl_rpn.c # foreach my $c (split(/([\?\"'+\-\*\/\^%\(\)\[\]{}])/, $r)) { if($c =~ /^0b[0-1_]+$/i || $c =~ /^0o[0-7_]+$/i || $c =~ /^0x[0-9a-f_]+$/i || $c =~ /^b['"](.*)['"]$/i || $c =~ /^([+-])?[0-9._]+([eE][0-9]+)?$/) { # Put ordinary number back... # push @r, &ano_cmd_par_op_number_op({ this => $c, cast => 'guess', line => undef() }); } elsif($c =~ /^[a-zA-Z0-9_]+$/) { if($c eq "rc" || $c eq "ZERO" || $c eq "NULL" || $c eq "INVALID") { # ...but skip predefined variable... # push @r, $c; } else { # ...skip defines... # if(defined($var_const{$c})) { if($c eq $var_r) { &msg_fail({ mess => "Recursion detected with '" . $c . "'" }); return; } $var_r = $c; push @r, &ano_out_par_number_op({ rpn => $var_const{$c}, not => $arg->{not} }); } else { # ...record usage of this variable... # $var_usage{$c}++; # ...put converted variable back... # if($arg->{not}) { push @r, $c; } else { if(!$var_store{$c}) { $var_store{$c} = &ano_out_par_variable_op_alias({ val => $c }); push @{ $var_these{$var_where} }, "PUT:RPN" . "\t" . $c . " -> " . $var_store{$c}; } else { push @{ $var_these{$var_where} }, "GET:RPN" . "\t" . $var_store{$c} . " <- " . $c; } push @r, $var_store{$c}; } } } } else { # ...and the operands # push @r, $c; } } return join("", @r); } sub ano_out_par_string { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad}); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_s dsl_cmd_" . $arg->{cmd} . $p . "_s_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; print STDOUT "\t" . "{ { (\"" . &ano_out_hex_bytes({ str => $arg->{val} }) . "\"), " . &ano_out_len_bytes({ str => $arg->{val} }) . ", 0 }," . "\n"; if($arg->{mod} eq "CHARSET_DEFAULT") { print STDOUT "\t" . " { " . $arg->{mod} . ", " . $arg->{mod} . "_SIZE, 0 } }" . "\n"; } else { print STDOUT "\t" . " { (\"" . &ano_out_hex_bytes({ str => $arg->{mod} }) . "\"), " . &ano_out_len_bytes({ str => $arg->{mod} }) . ", 0 } }" . "\n"; } print STDOUT "};" . "\n\n"; } sub ano_out_par_string_vanilla { my ($arg) = @_; my $p = ""; my $v = $arg->{val}; $p = $arg->{pad} if($arg->{pad}); # Remove possible casting and quotes at this point # $v =~ s/^.*?['"]//; $v =~ s/['"]\s*$//; print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_s dsl_cmd_" . $arg->{cmd} . $p . "_s_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; print STDOUT "\t" . "{ { \"" . $v . "\", " . &ano_out_len_bytes({ str => $v }) . ", 0 }," . "\n"; if($arg->{mod} eq "CHARSET_DEFAULT") { print STDOUT "\t" . " { " . $arg->{mod} . ", " . $arg->{mod} . "_SIZE, 0 } }" . "\n"; } else { print STDOUT "\t" . " { (\"" . &ano_out_hex_bytes({ str => $arg->{mod} }) . "\"), " . &ano_out_len_bytes({ str => $arg->{mod} }) . ", 0 } }" . "\n"; } print STDOUT "};" . "\n\n"; } sub ano_out_par_blob { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad}); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_b dsl_cmd_" . $arg->{cmd} . $p . "_b_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; print STDOUT "\t" . "{ " . $arg->{mod} . "," . "\n" . "\t\t" . "(struct dsl_member_types_t *) __" . $arg->{val} . "_t }" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_out_par_pointer { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad}); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_p dsl_cmd_" . $arg->{cmd} . $p . "_p_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; print STDOUT "\t" . "{ (void *) " . $arg->{val} . " }" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_out_par_handle { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad}); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_h dsl_cmd_" . $arg->{cmd} . $p . "_h_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; print STDOUT "\t" . "{ " . $arg->{val} . " }" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_out_par_color { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad}); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_c dsl_cmd_" . $arg->{cmd} . $p . "_c_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; if($arg->{mbr} && $arg->{mbr} ne "") { print STDOUT "\t" . "DSL_MEMBER_TYPE_" . uc($arg->{mbr}) . "," . "\n"; } else { print STDOUT "\t" . "DSL_MEMBER_TYPE_NONE," . "\n"; } print STDOUT "#if defined(IS_BIGENDIAN)" . "\n"; print STDOUT "\t" . "{ { { { " . join(', ', split(/,/, $arg->{val})) . " } } } }" . "\n"; print STDOUT "#else" . "\n"; print STDOUT "\t" . "{ { { { " . join(', ', reverse(split(/,/, $arg->{val}))) . " } } } }" . "\n"; print STDOUT "#endif" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_out_par_image { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad}); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_m dsl_cmd_" . $arg->{cmd} . $p . "_m_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; if($arg->{mbr} && $arg->{mbr} ne "") { print STDOUT "\t" . "DSL_MEMBER_TYPE_" . uc($arg->{mbr}) . "," . "\n"; } else { print STDOUT "\t" . "DSL_MEMBER_TYPE_NONE," . "\n"; } print STDOUT "\t" . "{ (\"" . &ano_out_hex_bytes({ str => $arg->{val} }) . "\"), { 0, 0, NULL } }" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_out_par_point { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad}); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_t dsl_cmd_" . $arg->{cmd} . $p . "_t_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; if($arg->{mbr} && $arg->{mbr} ne "") { print STDOUT "\t" . "DSL_MEMBER_TYPE_" . uc($arg->{mbr}) . "," . "\n"; } else { print STDOUT "\t" . "DSL_MEMBER_TYPE_NONE," . "\n"; } print STDOUT "\t" . "{ { " . $arg->{val} . " } }" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_out_par_variable { my ($arg) = @_; my $p = ""; $p = $arg->{pad} if($arg->{pad} && $arg->{pad} ne ""); print STDOUT "static struct dsl_cmd_" . $arg->{cmd} . $p . "_v dsl_cmd_" . $arg->{cmd} . $p . "_v_" . $arg->{cnt} . "_" . $arg->{i} . " = {" . "\n"; &ano_out_par_variable_op({ val => $arg->{val}, mod => $arg->{mod}, mbr => $arg->{mbr} }); print STDOUT "};" . "\n\n"; } sub ano_out_par_variable_op { my ($arg) = @_; my $var = ""; if($arg->{val} && $arg->{val} ne "") { # Record usage of this variable... # $var_usage{$arg->{val}}++; # ...and optimize variable names if needed # if(&alt_flags_check({ flag => 'VAR_NAME_SUBS' })) { # Do not alias predefined variables # if($arg->{val} eq "rc" || $arg->{val} eq "ZERO" || $arg->{val} eq "NULL" || $arg->{val} eq "INVALID") { $var = $arg->{val}; } else { my $e = ""; if($arg->{mod} ne 'NONE') { $e = " (predefined " . lc($arg->{mod}) . ")"; } if(!$var_store{$arg->{val}}) { $var_store{$arg->{val}} = &ano_out_par_variable_op_alias({ val => $arg->{val} }); push @{ $var_these{$var_where} }, "PUT" . "\t" . $arg->{val} . " -> " . $var_store{$arg->{val}} . $e; } else { push @{ $var_these{$var_where} }, "GET" . "\t" . $var_store{$arg->{val}} . " <- " . $arg->{val}; } $var = $var_store{$arg->{val}}; } } else { $var = $arg->{val}; } } # Keep in sync with struct dsl_var (dsl_shr.h) # print STDOUT "\t" . "{ DSL_PARAM_TYPE_" . $arg->{mod} . ", " . $arg->{mbr} . "," . "\n"; print STDOUT "\t" . "{ { (\"" . &ano_out_hex_bytes({ str => $var }) . "\"), " . &ano_out_len_bytes({ str => $var }) . ", 0 }," . "\n"; print STDOUT "\t" . " { CHARSET_DEFAULT, CHARSET_DEFAULT_SIZE, 0 } }," . "\n"; # if($arg->{ntp}) { print STDOUT "\t" . " { " . $arg->{ntp} . "," . "\n"; } else { print STDOUT "\t" . "{ DSL_NUMBER_TYPE_DEFAULT," . "\n"; } if($arg->{num}) { print STDOUT "\t" . " { " . $arg->{num} . " }," . "\n"; } else { print STDOUT "\t" . " { 0.0 }," . "\n"; } # print STDOUT "\t" . " { { { NULL, 0, 0 }, { NULL, 0, 0 } }," . "\n"; print STDOUT "\t" . " IS_NO, 0.0 }" . "\n"; print STDOUT "\t" . "}," . "\n"; # if($arg->{str}) { print STDOUT "\t" . "{ { (\"" . &ano_out_hex_bytes({ str => $arg->{str} }) . "\"), " . &ano_out_len_bytes({ str => $arg->{str} }) . ", 0 }," . "\n"; } else { print STDOUT "\t" . "{ { NULL, 0, 0 }," . "\n"; } if($arg->{chr}) { print STDOUT "\t" . " { (\"" . &ano_out_hex_bytes({ str => $arg->{chr} }) . "\"), " . &ano_out_len_bytes({ str => $arg->{chr} }) . ", 0 } }," . "\n"; } else { print STDOUT "\t" . " { CHARSET_DEFAULT, CHARSET_DEFAULT_SIZE, 0 } }," . "\n"; } # if($arg->{blt} && $arg->{bls}) { print STDOUT "\t" . "{ " . $arg->{blt} . "," . "\n" . "\t\t" . $arg->{bls} . " }," . "\n"; } else { print STDOUT "\t" . "{ 0, NULL }," . "\n"; } print STDOUT "\t" . "{ NULL }," . "\n"; print STDOUT "\t" . "{ 0 }," . "\n"; print STDOUT "\t" . "{ { { { 0, 0, 0, 0 } } } }," . "\n"; print STDOUT "\t" . "{ NULL, { 0, 0, NULL } }," . "\n"; print STDOUT "\t" . "{ { 0.0, 0.0, 0.0 } }," . "\n"; print STDOUT "\t" . "{ 0, 0 } }"; if($arg->{end} && $arg->{end} ne "") { print STDOUT $arg->{end}; } print STDOUT "\n"; } sub ano_out_par_variable_op_alias { my ($arg) = @_; if($var_i >= @var_alias) { $var_i = 0; &ano_out_par_variable_op_alias_op(); } my $r = $var_alias[$var_i++]; # Keep '_' in front of variable if present # $r = "_" . $r if($arg->{val} =~ /^_/); return $r; } sub ano_out_par_variable_op_alias_op { my ($arg) = @_; # 'r' is missing on purpose, because we dont want to masquerade 'rc' variable # my $c = "{" . join(",", "a" .. "q", "s" .. "z") . "}"; @var_alias = glob "$c" x $var_p++; } sub ano_out_par_split { my ($arg) = @_; my @e = ('(', '"', '\''); my @f = (')', '"', '\''); my @s = split(//, $arg->{this}); # my $o = ','; if($arg->{mark} && $arg->{mark} ne "") { $o = $arg->{mark}; } # my $d = 0; my $k = 0; my $r = ""; my @r = (); for(my $i = 0, my $c = 0, my $p = ""; $i < @s; $i++) { if($s[$i] eq '\\') { if($i == (@s - 1)) { &msg_fail({ mess => "Unknown escape sequence with '" . $arg->{this} . "'", line => $arg->{line} }); return; } $r .= $s[++$i]; next; } # $c = 0; if($k == 0) { # Outside quoted part, look for possible quote... # for(my $j = 0; $j < @e; $j++) { if($s[$i] eq $e[$j]) { # Store char for another end to be checked later # $p = $f[$j]; $k++; $c++; last; } } # ...no quote here, look for a delimiter then # if($c == 0 && $s[$i] eq $o) { # Roll over spaces after the delimiter # for(my $n = ($i + 1); $n < @s; $n++) { if($s[$n] =~ /\s/) { $i++; } else { last; } } &ano_out_par_split_op({ this => $r, char => \@r, skip => $d }); $d = 0; $r = ""; $c++; } } else { # Inside quoted part, look for its end # if($s[$i] eq $p) { # Roll over spaces after the quote # for(my $n = ($i + 1); $n < @s; $n++) { if($s[$n] =~ /\s/) { $i++; } else { last; } } $d = 1; $p = ""; $k--; $c++; } } # If this char was quote or delimiter, skip it... # next if($c != 0); # ...otherwise store it for later use # $r .= $s[$i]; } # If there is no unterminated quote... # if($k != 0) { &msg_fail({ mess => "Unbalanced quote with '" . $arg->{this} . "'", line => $arg->{line} }); return; } # ...handle the residue # &ano_out_par_split_op({ this => $r, char => \@r, skip => $d }); return @r; } sub ano_out_par_split_op { my ($arg) = @_; my $r = $arg->{this}; if($r && $r ne "") { if($arg->{skip} == 0) { $r =~ s/^\s+//; $r =~ s/\s+$//; } push @{ $arg->{char} }, $r if($r ne ""); } } sub ano_out_hex_bytes { my ($arg) = @_; my $r = $arg->{str}; my $t = "\t" x 2; use bytes; $r =~ s/(.)/sprintf "\\x%2x", ord $1/seg; my @r = $r =~ /(.{1,64})/g; use utf8; return join("\"\n$t\"", @r); } sub ano_out_len_bytes { my ($arg) = @_; use bytes; my $r = length($arg->{str}); use utf8; return $r; } # sub ano_hdr { my ($arg) = @_; print STDOUT "/**" . "\n"; print STDOUT " *" . " This file is automatically generated." . " To make changes, edit source file" . "\n"; print STDOUT " *" . "\n"; foreach my $f (@{ $arg->{file } }) { $f =~ s/\*\//_\//go; $f =~ s/\/\*/\/_/go; print STDOUT " *" . " " . $f . "\n"; } print STDOUT " *" . "\n"; print STDOUT " *" . " and regenerate this file by running:" . "\n"; print STDOUT " *" . "\n"; print STDOUT " *" . " \$ " . $arg->{this}; foreach my $f (@{ $arg->{file} }) { $f =~ s/\*\//_\//go; $f =~ s/\/\*/\/_/go; print STDOUT " " . $f; } print STDOUT " > engine/dsl_ano.h" . "\n"; print STDOUT " *" . "\n"; print STDOUT " */" . "\n\n"; } sub ano_bgn { my ($arg) = @_; print STDOUT "static struct dsl_cmd_label_s dsl_cmd_pre_p_1 = {" . "\n"; print STDOUT "\t" . "{ { \"__begin\", 7, 0 }," . "\n"; print STDOUT "\t" . " { CHARSET_DEFAULT, CHARSET_DEFAULT_SIZE, 0 } }" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "static struct dsl_cmd_label dsl_cmd_pre_1 = {" . "\n"; print STDOUT "\t" . "DSL_PARAM_TYPE_STRING," . "\n"; print STDOUT "\t" . "0, 0," . "\n"; print STDOUT "\t" . "&dsl_cmd_pre_p_1," . "\n"; print STDOUT "\t" . "NULL" . "\n"; print STDOUT "};" . "\n\n"; &ano_bgn_op({ num => 2, par => "NONE", var => "DSL_GLOBAL_VAR_RC" }); &ano_bgn_op({ num => 3, par => "NUMBER", var => "DSL_GLOBAL_VAR_ZERO" }); &ano_bgn_op({ num => 4, par => "STRING", var => "DSL_GLOBAL_VAR_NULL" }); &ano_bgn_op({ num => 5, par => "HANDLE", var => "DSL_GLOBAL_VAR_INVALID" }); print STDOUT "static struct dsl_cmd_label_s dsl_cmd_post_p_1 = {" . "\n"; print STDOUT "\t" . "{ { \"__end\", 5, 0 }," . "\n"; print STDOUT "\t" . " { CHARSET_DEFAULT, CHARSET_DEFAULT_SIZE, 0 } }" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "static struct dsl_cmd_label dsl_cmd_post_1 = {" . "\n"; print STDOUT "\t" . "DSL_PARAM_TYPE_STRING," . "\n"; print STDOUT "\t" . "0, 0," . "\n"; print STDOUT "\t" . "&dsl_cmd_post_p_1," . "\n"; print STDOUT "\t" . "NULL" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "static struct dsl_cmd_end_n dsl_cmd_post_p_2 = {" . "\n"; print STDOUT "\t" . "{ DSL_NUMBER_TYPE_I8," . "\n"; print STDOUT "\t" . " { 0.0 }," . "\n"; print STDOUT "\t" . " { { { NULL, 0, 0 }, { NULL, 0, 0 } }," . "\n"; print STDOUT "\t" . " IS_NO, 0.0 }" . "\n"; print STDOUT "\t" . "}" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "static struct dsl_cmd_end dsl_cmd_post_2 = {" . "\n"; print STDOUT "\t" . "DSL_PARAM_TYPE_NUMBER, &dsl_cmd_post_p_2" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "static const struct dsl_cmd dsl_cmd_ano[] = {" . "\n"; print STDOUT "\t" . "{ DSL_COMMAND_LABEL, &dsl_cmd_pre_1 }," . "\n"; print STDOUT "\t" . "{ DSL_COMMAND_VAR, &dsl_cmd_pre_2 }," . "\n"; print STDOUT "\t" . "{ DSL_COMMAND_VAR, &dsl_cmd_pre_3 }," . "\n"; print STDOUT "\t" . "{ DSL_COMMAND_VAR, &dsl_cmd_pre_4 }," . "\n"; print STDOUT "\t" . "{ DSL_COMMAND_VAR, &dsl_cmd_pre_5 }," . "\n"; print STDOUT "\n"; } sub ano_bgn_op { my ($arg) = @_; print STDOUT "static struct dsl_cmd_var dsl_cmd_pre_" . $arg->{num} . " = {" . "\n"; print STDOUT "\t" . "{ DSL_PARAM_TYPE_" . $arg->{par} . ", DSL_MEMBER_TYPE_NONE," . "\n"; print STDOUT "\t" . "{ { " . $arg->{var} . ", " . $arg->{var} . "_SIZE, 0 }," . "\n"; print STDOUT "\t" . " { CHARSET_DEFAULT, CHARSET_DEFAULT_SIZE, 0 } }," . "\n"; print STDOUT "\t" . "{ DSL_NUMBER_TYPE_DEFAULT," . "\n"; print STDOUT "\t" . " { 0.0 }," . "\n"; print STDOUT "\t" . " { { { NULL, 0, 0 }, { NULL, 0, 0 } }," . "\n"; print STDOUT "\t" . " IS_NO, 0.0 }" . "\n"; print STDOUT "\t" . "}," . "\n"; print STDOUT "\t" . "{ { NULL, 0, 0 }," . "\n"; print STDOUT "\t" . " { CHARSET_DEFAULT, CHARSET_DEFAULT_SIZE, 0 } }," . "\n"; print STDOUT "\t" . "{ 0, NULL }," . "\n"; print STDOUT "\t" . "{ NULL }," . "\n"; print STDOUT "\t" . "{ 0 }," . "\n"; print STDOUT "\t" . "{ { { { 0, 0, 0, 0 } } } }," . "\n"; print STDOUT "\t" . "{ NULL, { 0, 0, NULL } }," . "\n"; print STDOUT "\t" . "{ { 0.0, 0.0, 0.0 } }," . "\n"; print STDOUT "\t" . "{ 0, 0 } }" . "\n"; print STDOUT "};" . "\n\n"; } sub ano_ftr { my ($arg) = @_; my @c = ( 'ANO_SCRIPT_NAME', 'ANO_SCRIPT_VERSION', 'ANO_SCRIPT_DESCRIPTION', 'ANO_SCRIPT_COPYRIGHT', 'TAG_ATTR_COMPANY', 'TAG_ATTR_CONTACT', 'TAG_ATTR_CREATED', 'TAG_ATTR_DEPARTMENT', 'TAG_ATTR_DESCRIPTION', 'TAG_ATTR_HOMEDIRECTORY', 'TAG_ATTR_HOMEPAGE', 'TAG_ATTR_MAIL', 'TAG_ATTR_NOTES', 'TAG_ATTR_OPTIONS', 'TAG_ATTR_ORGANIZATION', 'TAG_ATTR_ORIGINALNAME', 'TAG_ATTR_OWNER', 'TAG_ATTR_REMOTECONTROLPORT', 'TAG_ATTR_REMOTECONTROLPROTO', 'TAG_ATTR_SCRIPTPATH', 'TAG_ATTR_SEEALSO', 'TAG_ATTR_SERIALNUMBER' ); # print STDOUT "\n"; print STDOUT "\t" . "{ DSL_COMMAND_LABEL, &dsl_cmd_post_1 }," . "\n"; print STDOUT "\t" . "{ DSL_COMMAND_END, &dsl_cmd_post_2 }," . "\n"; print STDOUT "\n"; print STDOUT "\t" . "{ DSL_COMMAND_NONE, NULL }" . "\n"; print STDOUT "};" . "\n\n"; # print STDOUT "#define DSL_CMD_INFO_C " . @c . "\n\n"; print STDOUT "struct dsl_cmd_info {" . "\n"; print STDOUT "\t" . "const char *s, *v;" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "static const struct dsl_cmd_info dsl_cmd_info_t[DSL_CMD_INFO_C + 1] = {" . "\n"; foreach my $c (@c) { if($alt_store{'@' . $c} eq '') { print STDOUT "\t" . "{ NULL, NULL }," . "\n"; } else { print STDOUT "\t" . "{ " . "(\"" . &ano_out_hex_bytes({ str => '@' . $c }) . "\")," . "\n"; print STDOUT "\t\t" . "(\"" . &ano_out_hex_bytes({ str => $alt_store{'@' . $c} }) . "\") }," . "\n"; } } print STDOUT "\n"; print STDOUT "\t" . "/* This marks the end of the info array */" . "\n"; print STDOUT "\t" . "{ NULL, NULL }" . "\n"; print STDOUT "};" . "\n"; } sub ano_end { my ($arg) = @_; my $k = keys %alt_unveil; print STDOUT "\n"; print STDOUT "/* List of files to unveil */" . "\n"; print STDOUT "#if defined(HAVE_UNVEIL) && defined(PROG_HAS_UNVEIL)" . "\n"; print STDOUT "static const struct t_rst t_rst_t[" . ($k + 1) . "] = {" . "\n"; foreach my $f (sort { lc($a) cmp lc($b) } keys %alt_unveil) { print STDOUT "\t" . "{ \"" . $f . "\", \"" . $alt_unveil{$f} . "\" }," . "\n"; } print STDOUT "\n\t" . "{ NULL, NULL }" . "\n"; print STDOUT "};" . "\n"; print STDOUT "#endif" . "\n\n"; $k = keys %alt_remote; print STDOUT "/* List of functions not allowed to run remotely */" . "\n"; print STDOUT "#if ! defined(PROG_DISABLE_REMOTE)" . "\n"; print STDOUT "#define DSL_CMD_REMOTE_C " . $k . "\n\n"; print STDOUT "#if (DSL_CMD_REMOTE_C > 0)" . "\n"; print STDOUT "struct t_remote {" . "\n"; print STDOUT "\t" . "unsigned int c;" . "\n\n"; print STDOUT "\t" . "const char *s;" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "static const struct t_remote t_remote_t[" . ($k + 1) . "] = {" . "\n"; foreach my $f (sort { lc($a) cmp lc($b) } keys %alt_remote) { print STDOUT "\t" . "{ " . $alt_remote{$f} . ", \"" . $f . "\" }," . "\n"; } print STDOUT "\n\t" . "{ 0, NULL }" . "\n"; print STDOUT "};" . "\n"; print STDOUT "#endif" . "\n"; print STDOUT "#endif" . "\n\n"; my $e = $arg->{ano}; $e =~ s/"/\\"/go; print STDOUT "#define DSL_COMPILER_VER \"" . $DSL_COMPILER_VER . "\"" . "\n"; print STDOUT "#define DSL_EMBEDDED_ANO \"" . $e . "\"" . "\n\n"; # print STDOUT "/* " . int($arg->{cnt}) . " items processed at " . localtime() . " */" . "\n"; } # sub ano_out_min { my ($arg) = @_; &ano_bgn(); &ano_ftr(); print STDOUT "\n"; print STDOUT "/* List of files to unveil */" . "\n"; print STDOUT "#if defined(HAVE_UNVEIL) && defined(PROG_HAS_UNVEIL)" . "\n"; print STDOUT "static const struct t_rst t_rst_t[1] = {" . "\n"; print STDOUT "\t" . "{ NULL, NULL }" . "\n"; print STDOUT "};" . "\n"; print STDOUT "#endif" . "\n\n"; print STDOUT "/* List of functions not allowed to run remotely */" . "\n"; print STDOUT "#if ! defined(PROG_DISABLE_REMOTE)" . "\n"; print STDOUT "#define DSL_CMD_REMOTE_C 0" . "\n\n"; print STDOUT "#if (DSL_CMD_REMOTE_C > 0)" . "\n"; print STDOUT "struct t_remote {" . "\n"; print STDOUT "\t" . "unsigned int c;" . "\n\n"; print STDOUT "\t" . "const char *s;" . "\n"; print STDOUT "};" . "\n\n"; print STDOUT "static const struct t_remote t_remote_t[1] = {" . "\n"; print STDOUT "\t" . "{ 0, NULL }" . "\n"; print STDOUT "};" . "\n"; print STDOUT "#endif" . "\n"; print STDOUT "#endif" . "\n\n"; print STDOUT "#define DSL_COMPILER_VER \"" . $DSL_COMPILER_VER . "\"" . "\n"; print STDOUT "#define DSL_EMBEDDED_ANO \"" . "empty" . "\"" . "\n"; exit(0); } # sub msg_warn { my ($arg) = @_; my $p; my $r = $arg->{mess}; $r =~ s/\.*$//; # if($arg->{line}) { my $n = $arg->{line}; my @c = &pre_inc_macro(); $n -= @c; # if(!$arg->{fail}) { print STDOUT "#warning " . $r . " near line " . $n . "\n\n"; } print STDERR $0 . ": " . $r . " near line " . $n . "." . "\n"; undef(@c); } else { if(!$arg->{fail}) { print STDOUT "#warning " . $r . "\n\n"; } print STDERR $0 . ": " . $r . "." . "\n"; } # $p = $arg->{show} if($arg->{show}); if($p) { my $s = 0; $s = $arg->{skip} if($arg->{skip}); print STDERR "\n"; for(my $i = 0; $i < 5; $i++) { if(@file_src[($p - 3) + $i]) { next if((($p - $s - 2) + $i) <= 0); print STDERR ($p - $s - 2) + $i . " | " . @file_src[($p - 3) + $i]; } } print STDERR "\n"; } } sub msg_fail { my ($arg) = @_; if($arg->{line}) { my $n = $arg->{line}; my @c = &pre_inc_macro(); $n -= @c; # print STDOUT "#error " . $arg->{mess} . " near line " . $n . "\n\n"; &msg_warn({ mess => $arg->{mess} . " near line " . $n . ". Abort.", show => $arg->{line}, skip => int(@c), fail => 1 }); undef(@c); } else { print STDOUT "#error " . $arg->{mess} . "\n\n"; &msg_warn({ mess => $arg->{mess} . ". Abort.", fail => 1 }); } exit(1); } # sub arg_cmd_fetch { my ($arg) = @_; if($arg_store{$arg->{arg}}) { return $arg_store{$arg->{arg}}; } return undef(); } sub arg_cmd_init { my ($arg) = @_; %arg_types = &arg_cmd_types(); for(my $i = 0; $i < @ARGV; $i++) { my $s = $ARGV[$i]; if($s =~ /^-/) { if(!$arg_types{$s}) { &msg_fail({ mess => "Unknown option " . $s . ", please try " . $0 . " --help" }); return; } if($arg_types{$s} == 1) { # This is help page # my %p = &arg_cmd_guide(); print STDOUT "\n" . "Usage: $0 [OPTIONS] [[FILE] [FILE] [...]]" . "\n\n"; foreach my $h (sort { lc($a) cmp lc($b) } keys %p) { my $s = $h; $s =~ s/^..\s+//; print STDOUT " " . $s . " " x (12 - length($s)) . $p{$h} . "\n"; } print STDOUT "\n"; exit(0); } elsif($arg_types{$s} == 2) { # This dumps something # if($s eq '-dm') { print STDERR join("", @pre_inc_n); } exit(0); } elsif($arg_types{$s} == 3) { # This option is on/off switch # $arg_store{$s} = 1; } elsif($arg_types{$s} == 4) { # This option is integer # $arg_store{$s} = $ARGV[++$i] + 0; } elsif($arg_types{$s} == 5) { # This option is string # $arg_store{$s} = $ARGV[++$i] . ""; } } else { # Options not starting with dash are treated as source files # my $p = $arg_store{'ano_sources'}; push @{ $p }, $s; } } } sub arg_cmd_types { my ($arg) = @_; # Command line option types: # 1 = help page # 2 = dump something to stderr # 3 = on/off switch # 4 = parameter is integer # 5 = parameter is string # my %r = ( '-dm' => 2, '-dn' => 3, '-ds' => 3, '-dv' => 3, '-of' => 5, '-h' => 1, '--help' => 1 ); return %r; } sub arg_cmd_guide { my ($arg) = @_; # 'AA ' prefix is for sorting # my %r = ( 'AA -dm' => 'List predefined helper macros to stderr and quit', 'AB -dn' => 'Prepend line numbers when dumping preprocessed source with -ds switch', 'AC -ds' => 'Dump preprocessed source to stderr after compilation', 'AD -dv' => 'Dump variable alias table to stderr after compilation', 'AE -of ' => 'Write compiled source to ' ); return %r; } # sub alt_flags_check { my ($arg) = @_; my $c = '@ANO_FLAGS_' . $arg->{flag}; if($alt_flags{$c}) { # Check for true, yes, 1 or [x] # if($alt_flags{$c} =~ /^t/i || $alt_flags{$c} =~ /^y/i || $alt_flags{$c} =~ /^1/ || $alt_flags{$c} =~ /^\[\s*x\s*\]/i) { return 1; } } return undef(); } sub alt_par_names { my ($arg) = @_; if(open(FILE, '<:encoding(UTF-8)', $arg->{file})) { my $r = ""; # Cleanup the named parameter definitions first... # while(my $f = ) { $f =~ s/\r+|\n//; $f =~ s/\\$//; $f =~ s/\).*$/)/; $f =~ s/\s+//g; next if($f =~ /^;/ || $f eq ""); $r .= $f; } close(FILE); # ...and fill the named parameter table # $r =~ s/\)/\n/g; foreach my $f (split(/\n/, $r)) { my @k = split(/\s*\(\s*|,/, $f); # Initialize empty named parameter tables for this function... # $fnc_par_n{$k[0]} = {}; $fnc_par_n{$k[0] . ":types"} = {}; for(my $i = 1; $i < @k; $i++) { my @j = split(/:/, $k[$i], 2); if(@j == 1) { # ...fix this if type is missing... # unshift @j, ''; } # ...store parameter name for later use... # $fnc_par_n{$k[0]}{$j[1]} = $i; # ...and its type # $fnc_par_n{$k[0] . ":types"}{$j[1]} = $j[0]; } } } else { &msg_fail({ mess => "Failed to open named parameter file '" . $arg->{file} . "': " . $!, line => $arg->{line} }); return; } } sub fnc_par_names { my ($arg) = @_; # Named parameter order numbers begins from one, # order number is how the engine expects parameters # my %c = ( 'audio_cancel' => { 'audio_handle' => 1 }, 'audio_cancel:types' => { 'audio_handle' => 'handle' }, 'audio_close' => { 'audio_handle' => 1 }, 'audio_close:types' => { 'audio_handle' => 'handle' }, 'audio_create_noise_white' => { 'seconds' => 1 }, 'audio_create_noise_white:types' => { 'seconds' => 'f64' }, 'audio_create_wave_random' => { 'seconds' => 1, 'frequency' => 2, 'amplitude' => 3 }, 'audio_create_wave_random:types' => { 'seconds' => 'f64', 'frequency' => 'f64', 'amplitude' => 'f64' }, 'audio_create_wave_sine' => { 'seconds' => 1, 'frequency' => 2 }, 'audio_create_wave_sine:types' => { 'seconds' => 'f64', 'frequency' => 'f64' }, 'audio_create_wave_square' => { 'seconds' => 1, 'frequency' => 2 }, 'audio_create_wave_square:types' => { 'seconds' => 'f64', 'frequency' => 'f64' }, 'audio_cut' => { 'audio_handle' => 1 }, 'audio_cut:types' => { 'audio_handle' => 'handle' }, 'audio_hold' => { 'audio_handle' => 1 }, 'audio_hold:types' => { 'audio_handle' => 'handle' }, 'audio_init' => { }, 'audio_init:types' => { }, 'audio_master_dec' => { 'value' => 1 }, 'audio_master_dec:types' => { 'value' => 'f32' }, 'audio_master_get' => { }, 'audio_master_get:types' => { }, 'audio_master_inc' => { 'value' => 1 }, 'audio_master_inc:types' => { 'value' => 'f32' }, 'audio_master_set' => { 'value' => 1 }, 'audio_master_set:types' => { 'value' => 'f32' }, 'audio_open' => { 'audio_file' => 1 }, 'audio_open:types' => { 'audio_file' => 'default' }, 'audio_pan_dec' => { 'audio_handle' => 1, 'value' => 2 }, 'audio_pan_dec:types' => { 'audio_handle' => 'handle', 'value' => 'f32' }, 'audio_pan_get' => { 'audio_handle' => 1 }, 'audio_pan_get:types' => { 'audio_handle' => 'handle' }, 'audio_pan_inc' => { 'audio_handle' => 1, 'value' => 2 }, 'audio_pan_inc:types' => { 'audio_handle' => 'handle', 'value' => 'f32' }, 'audio_pan_set' => { 'audio_handle' => 1, 'value' => 2 }, 'audio_pan_set:types' => { 'audio_handle' => 'handle', 'value' => 'f32' }, 'audio_play' => { 'audio_handle' => 1, 'volume' => 2, 'pan' => 3 }, 'audio_play:types' => { 'audio_handle' => 'handle', 'volume' => 'f32', 'pan' => 'f32' }, 'audio_solo' => { 'audio_handle' => 1 }, 'audio_solo:types' => { 'audio_handle' => 'handle' }, 'audio_vol_dec' => { 'audio_handle' => 1, 'value' => 2 }, 'audio_vol_dec:types' => { 'audio_handle' => 'handle', 'value' => 'f32' }, 'audio_vol_get' => { 'audio_handle' => 1 }, 'audio_vol_get:types' => { 'audio_handle' => 'handle' }, 'audio_vol_inc' => { 'audio_handle' => 1, 'value' => 2 }, 'audio_vol_inc:types' => { 'audio_handle' => 'handle', 'value' => 'f32' }, 'audio_vol_set' => { 'audio_handle' => 1, 'value' => 2 }, 'audio_vol_set:types' => { 'audio_handle' => 'handle', 'value' => 'f32' }, 'audio_wait' => { 'audio_handle' => 1 }, 'audio_wait:types' => { 'audio_handle' => 'handle' }, 'bob_get_altitude' => { 'container' => 1, 'bob' => 2 }, 'bob_get_altitude:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_altitude' => { 'container' => 1, 'bob' => 2, 'altitude' => 3 }, 'bob_set_altitude:types' => { 'container' => 'handle', 'bob' => 'handle', 'altitude' => 'uint' }, 'bob_add_altitude' => { 'container' => 1, 'bob' => 2, 'altitude' => 3 }, 'bob_add_altitude:types' => { 'container' => 'handle', 'bob' => 'handle', 'altitude' => 'int' }, 'bob_sub_altitude' => { 'container' => 1, 'bob' => 2, 'altitude' => 3 }, 'bob_sub_altitude:types' => { 'container' => 'handle', 'bob' => 'handle', 'altitude' => 'int' }, 'bob_get_x_position' => { 'container' => 1, 'bob' => 2 }, 'bob_get_x_position:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_get_y_position' => { 'container' => 1, 'bob' => 2 }, 'bob_get_y_position:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_position' => { 'container' => 1, 'bob' => 2, 'x' => 3, 'y' => 4 }, 'bob_set_position:types' => { 'container' => 'handle', 'bob' => 'handle', 'x' => 'int', 'y' => 'int' }, 'bob_set_x_position' => { 'container' => 1, 'bob' => 2, 'x' => 3 }, 'bob_set_x_position:types' => { 'container' => 'handle', 'bob' => 'handle', 'x' => 'int' }, 'bob_set_y_position' => { 'container' => 1, 'bob' => 2, 'y' => 3 }, 'bob_set_y_position:types' => { 'container' => 'handle', 'bob' => 'handle', 'y' => 'int' }, 'bob_add_x_position' => { 'container' => 1, 'bob' => 2, 'x' => 3 }, 'bob_add_x_position:types' => { 'container' => 'handle', 'bob' => 'handle', 'x' => 'int' }, 'bob_add_y_position' => { 'container' => 1, 'bob' => 2, 'y' => 3 }, 'bob_add_y_position:types' => { 'container' => 'handle', 'bob' => 'handle', 'y' => 'int' }, 'bob_sub_x_position' => { 'container' => 1, 'bob' => 2, 'x' => 3 }, 'bob_sub_x_position:types' => { 'container' => 'handle', 'bob' => 'handle', 'x' => 'int' }, 'bob_sub_y_position' => { 'container' => 1, 'bob' => 2, 'y' => 3 }, 'bob_sub_y_position:types' => { 'container' => 'handle', 'bob' => 'handle', 'y' => 'int' }, 'bob_get_angle' => { 'container' => 1, 'bob' => 2 }, 'bob_get_angle:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_angle_position' => { 'container' => 1, 'bob' => 2, 'angle' => 3, 'distance' => 4 }, 'bob_set_angle_position:types' => { 'container' => 'handle', 'bob' => 'handle', 'angle' => 'f64', 'distance' => 'f64' }, 'bob_get_depth' => { 'container' => 1, 'bob' => 2 }, 'bob_get_depth:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_depth' => { 'container' => 1, 'bob' => 2, 'depth' => 3 }, 'bob_set_depth:types' => { 'container' => 'handle', 'bob' => 'handle', 'depth' => 'int' }, 'bob_get_distance' => { 'from_container' => 1, 'from_bob' => 2, 'to_container' => 3, 'to_bob' => 4 }, 'bob_get_distance:types' => { 'from_container' => 'handle', 'from_bob' => 'handle', 'to_container' => 'handle', 'to_bob' => 'handle' }, 'bob_get_measure' => { 'container' => 1, 'bob' => 2, 'x' => 3, 'y' => 4 }, 'bob_get_measure:types' => { 'container' => 'handle', 'bob' => 'handle', 'x' => 'int', 'y' => 'int' }, 'bob_get_map' => { 'container' => 1, 'bob' => 2 }, 'bob_get_map:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_map' => { 'container' => 1, 'bob' => 2, 'map' => 3 }, 'bob_set_map:types' => { 'container' => 'handle', 'bob' => 'handle', 'map' => 'uint' }, 'bob_get_playdirection' => { 'container' => 1, 'bob' => 2 }, 'bob_get_playdirection:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_playdirection' => { 'container' => 1, 'bob' => 2, 'playdirection' => 3 }, 'bob_set_playdirection:types' => { 'container' => 'handle', 'bob' => 'handle', 'playdirection' => 'uint' }, 'bob_get_playmode' => { 'container' => 1, 'bob' => 2 }, 'bob_get_playmode:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_playmode' => { 'container' => 1, 'bob' => 2, 'playmode' => 3 }, 'bob_set_playmode:types' => { 'container' => 'handle', 'bob' => 'handle', 'playmode' => 'uint' }, 'bob_get_playskip' => { 'container' => 1, 'bob' => 2 }, 'bob_get_playskip:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_playskip' => { 'container' => 1, 'bob' => 2, 'playskip' => 3 }, 'bob_set_playskip:types' => { 'container' => 'handle', 'bob' => 'handle', 'playskip' => 'uint' }, 'bob_get_playspeed' => { 'container' => 1, 'bob' => 2 }, 'bob_get_playspeed:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_set_playspeed' => { 'container' => 1, 'bob' => 2, 'playspeed' => 3 }, 'bob_set_playspeed:types' => { 'container' => 'handle', 'bob' => 'handle', 'playspeed' => 'f64' }, 'bob_set_frame' => { 'container' => 1, 'bob' => 2, 'frame' => 3 }, 'bob_set_frame:types' => { 'container' => 'handle', 'bob' => 'handle', 'frame' => 'uint' }, 'bob_add_frame' => { 'container' => 1, 'bob' => 2, 'frame' => 3 }, 'bob_add_frame:types' => { 'container' => 'handle', 'bob' => 'handle', 'frame' => 'int' }, 'bob_sub_frame' => { 'container' => 1, 'bob' => 2, 'frame' => 3 }, 'bob_sub_frame:types' => { 'container' => 'handle', 'bob' => 'handle', 'frame' => 'int' }, 'bob_get_container_depth' => { 'container' => 1 }, 'bob_get_container_depth:types' => { 'container' => 'handle' }, 'bob_set_container_depth' => { 'container' => 1, 'depth' => 2 }, 'bob_set_container_depth:types' => { 'container' => 'handle', 'depth' => 'int' }, 'bob_create' => { 'file' => 1, 'container' => 2, 'altitude' => 3, 'x' => 4, 'y' => 5, 'depth' => 6 }, 'bob_create:types' => { 'file' => 'handle', 'container' => 'handle', 'altitude' => 'uint', 'x' => 'int', 'y' => 'int', 'depth' => 'int' }, 'bob_create_background' => { 'file' => 1, 'container' => 2, 'opaque' => 3, 'depth' => 4 }, 'bob_create_background:types' => { 'file' => 'handle', 'container' => 'handle', 'opaque' => 'uint', 'depth' => 'int' }, 'bob_create_container' => { 'handle' => 1, 'depth' => 2 }, 'bob_create_container:types' => { 'handle' => 'handle', 'depth' => 'int' }, 'bob_delete' => { 'container' => 1, 'bob' => 2 }, 'bob_delete:types' => { 'container' => 'handle', 'bob' => 'handle' }, 'bob_delete_container' => { 'container' => 1 }, 'bob_delete_container:types' => { 'container' => 'handle' }, 'bob_init_file' => { 'name' => 1 }, 'bob_init_file:types' => { 'name' => 'default' }, 'bob_init_image' => { 'width' => 1, 'height' => 2 }, 'bob_init_image:types' => { 'width' => 'uint', 'height' => 'uint' }, 'bob_free_file' => { 'file' => 1 }, 'bob_free_file:types' => { 'file' => 'handle' }, 'bob_free_image' => { 'image' => 1 }, 'bob_free_image:types' => { 'image' => 'handle' }, 'clock_get_multiplier' => { }, 'clock_get_multiplier:types' => { }, 'clock_get_ticks' => { }, 'clock_get_ticks:types' => { }, 'clock_set' => { 'value' => 1 }, 'clock_set:types' => { 'value' => 'f64' }, 'clock_set_multiplier' => { 'value' => 1 }, 'clock_set_multiplier:types' => { 'value' => 'f64' }, 'color_brightness' => { 'color' => 1 }, 'color_brightness:types' => { 'color' => 'color' }, 'color_complement' => { 'color' => 1 }, 'color_complement:types' => { 'color' => 'color' }, 'color_mix' => { 'color1' => 1, 'color2' => 2, 'factor' => 3 }, 'color_mix:types' => { 'color1' => 'color', 'color2' => 'color', 'factor' => 'f32' }, 'coords_difference_2d' => { 'point1' => 1, 'point2' => 2 }, 'coords_difference_2d:types' => { 'point1' => 'point', 'point2' => 'point' }, 'coords_difference_3d' => { 'point1' => 1, 'point2' => 2 }, 'coords_difference_3d:types' => { 'point1' => 'point', 'point2' => 'point' }, 'coords_dot_product' => { 'point1' => 1, 'point2' => 2 }, 'coords_dot_product:types' => { 'point1' => 'point', 'point2' => 'point' }, 'coords_get_angle' => { 'point' => 1 }, 'coords_get_angle:types' => { 'point' => 'point' }, 'coords_get_pos' => { 'angle' => 1, 'distance' => 2 }, 'coords_get_pos:types' => { 'angle' => 'f64', 'distance' => 'f64' }, 'coords_intp_catmull_x' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5 }, 'coords_intp_catmull_x:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64' }, 'coords_intp_catmull_y' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5 }, 'coords_intp_catmull_y:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64' }, 'coords_intp_catmull_z' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5 }, 'coords_intp_catmull_z:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64' }, 'coords_intp_cubic_x' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5 }, 'coords_intp_cubic_x:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64' }, 'coords_intp_cubic_y' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5 }, 'coords_intp_cubic_y:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64' }, 'coords_intp_cubic_z' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5 }, 'coords_intp_cubic_z:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64' }, 'coords_intp_hermite_x' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5, 'bias' => 6, 'tension' => 7 }, 'coords_intp_hermite_x:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64', 'bias' => 'f64', 'tension' => 'f64' }, 'coords_intp_hermite_y' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5, 'bias' => 6, 'tension' => 7 }, 'coords_intp_hermite_y:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64', 'bias' => 'f64', 'tension' => 'f64' }, 'coords_intp_hermite_z' => { 'point1' => 1, 'point2' => 2, 'point3' => 3, 'point4' => 4, 'interpolation_point' => 5, 'bias' => 6, 'tension' => 7 }, 'coords_intp_hermite_z:types' => { 'point1' => 'point', 'point2' => 'point', 'point3' => 'point', 'point4' => 'point', 'interpolation_point' => 'f64', 'bias' => 'f64', 'tension' => 'f64' }, 'coords_intp_linear_x' => { 'point1' => 1, 'point2' => 2, 'interpolation_point' => 3 }, 'coords_intp_linear_x:types' => { 'point1' => 'point', 'point2' => 'point', 'interpolation_point' => 'f64' }, 'coords_intp_linear_y' => { 'point1' => 1, 'point2' => 2, 'interpolation_point' => 3 }, 'coords_intp_linear_y:types' => { 'point1' => 'point', 'point2' => 'point', 'interpolation_point' => 'f64' }, 'coords_intp_linear_z' => { 'point1' => 1, 'point2' => 2, 'interpolation_point' => 3 }, 'coords_intp_linear_z:types' => { 'point1' => 'point', 'point2' => 'point', 'interpolation_point' => 'f64' }, 'coords_mag_2d' => { 'point' => 1 }, 'coords_mag_2d:types' => { 'point' => 'point' }, 'coords_mag_3d' => { 'point' => 1 }, 'coords_mag_3d:types' => { 'point' => 'point' }, 'coords_normalize_2d' => { 'point' => 1 }, 'coords_normalize_2d:types' => { 'point' => 'point' }, 'coords_normalize_3d' => { 'point' => 1 }, 'coords_normalize_3d:types' => { 'point' => 'point' }, 'draw_border' => { 'window_handle' => 1, 'position_x' => 2, 'position_y' => 3, 'width' => 4, 'height' => 5, 'thickness' => 6, 'color' => 7 }, 'draw_border:types' => { 'window_handle' => 'handle', 'position_x' => 'int', 'position_y' => 'int', 'width' => 'uint', 'height' => 'uint', 'thickness' => 'uint', 'color' => 'color' }, 'draw_border_alpha' => { 'window_handle' => 1, 'position_x' => 2, 'position_y' => 3, 'width' => 4, 'height' => 5, 'thickness' => 6, 'color' => 7 }, 'draw_border_alpha:types' => { 'window_handle' => 'handle', 'position_x' => 'int', 'position_y' => 'int', 'width' => 'uint', 'height' => 'uint', 'thickness' => 'uint', 'color' => 'color' }, 'draw_copy' => { 'window_handle' => 1, 'source_area_x' => 2, 'source_area_y' => 3, 'destination_area_x' => 4, 'destination_area_y' => 5, 'area_width' => 6, 'area_height' => 7 }, 'draw_copy:types' => { 'window_handle' => 'handle', 'source_area_x' => 'int', 'source_area_y' => 'int', 'destination_area_x' => 'int', 'destination_area_y' => 'int', 'area_width' => 'uint', 'area_height' => 'uint' }, 'draw_copy_alpha' => { 'window_handle' => 1, 'source_area_x' => 2, 'source_area_y' => 3, 'destination_area_x' => 4, 'destination_area_y' => 5, 'area_width' => 6, 'area_height' => 7 }, 'draw_copy_alpha:types' => { 'window_handle' => 'handle', 'source_area_x' => 'int', 'source_area_y' => 'int', 'destination_area_x' => 'int', 'destination_area_y' => 'int', 'area_width' => 'uint', 'area_height' => 'uint' }, 'draw_pixel' => { 'window_handle' => 1, 'position_x' => 2, 'position_y' => 3, 'color' => 4 }, 'draw_pixel:types' => { 'window_handle' => 'handle', 'position_x' => 'int', 'position_y' => 'int', 'color' => 'color' }, 'draw_pixel_alpha' => { 'window_handle' => 1, 'position_x' => 2, 'position_y' => 3, 'color' => 4 }, 'draw_pixel_alpha:types' => { 'window_handle' => 'handle', 'position_x' => 'int', 'position_y' => 'int', 'color' => 'color' }, 'draw_set' => { 'window_handle' => 1, 'start_x' => 2, 'start_y' => 3, 'end_x' => 4, 'end_y' => 5, 'color' => 6 }, 'draw_set:types' => { 'window_handle' => 'handle', 'start_x' => 'int', 'start_y' => 'int', 'end_x' => 'int', 'end_y' => 'int', 'color' => 'color' }, 'draw_set_alpha' => { 'window_handle' => 1, 'start_x' => 2, 'start_y' => 3, 'end_x' => 4, 'end_y' => 5, 'color' => 6 }, 'draw_set_alpha:types' => { 'window_handle' => 'handle', 'start_x' => 'int', 'start_y' => 'int', 'end_x' => 'int', 'end_y' => 'int', 'color' => 'color' }, 'draw_subpixel' => { 'window_handle' => 1, 'position_x' => 2, 'position_y' => 3, 'color' => 4 }, 'draw_subpixel:types' => { 'window_handle' => 'handle', 'position_x' => 'f64', 'position_y' => 'f64', 'color' => 'color' }, 'draw_subpixel_alpha' => { 'window_handle' => 1, 'position_x' => 2, 'position_y' => 3, 'color' => 4 }, 'draw_subpixel_alpha:types' => { 'window_handle' => 'handle', 'position_x' => 'f64', 'position_y' => 'f64', 'color' => 'color' }, 'draw_text' => { 'window_handle' => 1, 'font_handle' => 2, 'position_x' => 3, 'position_y' => 4 }, 'draw_text:types' => { 'window_handle' => 'handle', 'font_handle' => 'handle', 'position_x' => 'int', 'position_y' => 'int' }, 'draw_wipe' => { 'window_handle' => 1 }, 'draw_wipe:types' => { 'window_handle' => 'handle' }, 'font_close' => { 'font_handle' => 1 }, 'font_close:types' => { 'font_handle' => 'handle' }, 'font_get_height' => { 'font_handle' => 1 }, 'font_get_height:types' => { 'font_handle' => 'handle' }, 'font_get_width' => { 'font_handle' => 1 }, 'font_get_width:types' => { 'font_handle' => 'handle' }, 'font_open' => { 'font_file' => 1, 'font_size' => 2, 'font_resolution' => 3 }, 'font_open:types' => { 'font_file' => 'default', 'font_size' => 'uint', 'font_resolution' => 'uint' }, 'font_open_copy' => { 'font_handle' => 1 }, 'font_open_copy:types' => { 'font_handle' => 'handle' }, 'font_render' => { 'font_handle' => 1, 'string_charset' => 2, 'string' => 3, 'string_length' => 4, 'color' => 5 }, 'font_render:types' => { 'font_handle' => 'handle', 'string_charset' => 'default', 'string' => 'default', 'string_length' => 'uint', 'color' => 'color' }, 'image_read' => { 'image_file' => 1 }, 'image_read:types' => { 'image_file' => 'default' }, 'image_read_bmp' => { 'image_file' => 1 }, 'image_read_bmp:types' => { 'image_file' => 'default' }, 'image_read_tga' => { 'image_file' => 1 }, 'image_read_tga:types' => { 'image_file' => 'default' }, 'image_write_bmp' => { 'image_file' => 1, 'image' => 2 }, 'image_write_bmp:types' => { 'image_file' => 'default', 'image' => 'image' }, 'image_write_cel' => { 'image_file' => 1, 'image' => 2 }, 'image_write_cel:types' => { 'image_file' => 'default', 'image' => 'image' }, 'image_write_pix' => { 'image_file' => 1, 'image' => 2 }, 'image_write_pix:types' => { 'image_file' => 'default', 'image' => 'image' }, 'image_write_ppm' => { 'image_file' => 1, 'image' => 2 }, 'image_write_ppm:types' => { 'image_file' => 'default', 'image' => 'image' }, 'image_write_ras' => { 'image_file' => 1, 'image' => 2 }, 'image_write_ras:types' => { 'image_file' => 'default', 'image' => 'image' }, 'image_write_rgb' => { 'image_file' => 1, 'image' => 2 }, 'image_write_rgb:types' => { 'image_file' => 'default', 'image' => 'image' }, 'image_write_rla' => { 'image_file' => 1, 'image' => 2 }, 'image_write_rla:types' => { 'image_file' => 'default', 'image' => 'image' }, 'image_write_tga' => { 'image_file' => 1, 'image' => 2 }, 'image_write_tga:types' => { 'image_file' => 'default', 'image' => 'image' }, 'math_clamp' => { 'value' => 1, 'min' => 2, 'max' => 3 }, 'math_clamp:types' => { 'value' => 'f64', 'min' => 'f64', 'max' => 'f64' }, 'math_get_hcf' => { 'value1' => 1, 'value2' => 2 }, 'math_get_hcf:types' => { 'value1' => 'f64', 'value2' => 'f64' }, 'math_map' => { 'value' => 1, 'current_min' => 2, 'current_max' => 3, 'mapped_min' => 4, 'mapped_max' => 5 }, 'math_map:types' => { 'value' => 'f64', 'current_min' => 'f64', 'current_max' => 'f64', 'mapped_min' => 'f64', 'mapped_max' => 'f64' }, 'menu_bar_hide' => { 'bar_id' => 1 }, 'menu_bar_hide:types' => { 'bar_id' => 'handle' }, 'menu_bar_show' => { 'bar_id' => 1 }, 'menu_bar_show:types' => { 'bar_id' => 'handle' }, 'menu_item_disable' => { 'bar_id' => 1, 'item_tag' => 2 }, 'menu_item_disable:types' => { 'bar_id' => 'handle', 'item_tag' => 'handle' }, 'menu_item_enable' => { 'bar_id' => 1, 'item_tag' => 2 }, 'menu_item_enable:types' => { 'bar_id' => 'handle', 'item_tag' => 'handle' }, # Exec parameter count can be anything between one and DYNLOAD_PARAM_MAX # 'exec' => { 'command' => 1 }, 'exec:types' => { 'command' => 'default' }, 'exit' => { 'exit_code' => 1 }, 'exit:types' => { 'exit_code' => 'i8' }, 'fork' => { }, 'fork:types' => { }, 'sleep' => { 'secs' => 1, 'nanosecs' => 2 }, 'sleep:types' => { 'secs' => 'long', 'nanosecs' => 'long' }, 'system' => { 'command' => 1 }, 'system:types' => { 'command' => 'default' }, 'time' => { }, 'time:types' => { }, 'timer' => { 'secs' => 1, 'nanosecs' => 2, 'timer' => 3 }, 'timer:types' => { 'secs' => 'long', 'nanosecs' => 'long', 'timer' => 'default' }, 'node_get_groupname' => { }, 'node_get_groupname:types' => { }, 'node_get_homedir' => { }, 'node_get_homedir:types' => { }, 'node_get_hostname' => { }, 'node_get_hostname:types' => { }, 'node_get_machine' => { }, 'node_get_machine:types' => { }, 'node_get_release' => { }, 'node_get_release:types' => { }, 'node_get_system' => { }, 'node_get_system:types' => { }, 'node_get_username' => { }, 'node_get_username:types' => { }, 'numa_affinity' => { 'domain' => 1, 'policy' => 2 }, 'numa_affinity:types' => { 'domain' => 'int', 'policy' => 'int' }, 'remote_init' => { }, 'remote_init:types' => { }, 'thread_abort' => { 'thread_name' => 1 }, 'thread_abort:types' => { 'thread_name' => 'default' }, 'thread_abort_all' => { }, 'thread_abort_all:types' => { }, 'thread_affinity' => { 'cpu' => 1 }, 'thread_affinity:types' => { 'cpu' => 'int' }, 'thread_guard_size' => { 'size' => 1 }, 'thread_guard_size:types' => { 'size' => 'usize' }, 'thread_spawn' => { 'thread_name' => 1, 'thread_function' => 2 }, 'thread_spawn:types' => { 'thread_name' => 'default', 'thread_function' => 'default' }, 'thread_stack_size' => { 'size' => 1 }, 'thread_stack_size:types' => { 'size' => 'usize' }, 'thread_wait' => { 'thread_name' => 1 }, 'thread_wait:types' => { 'thread_name' => 'default' }, 'thread_wait_all' => { }, 'thread_wait_all:types' => { }, 'widget_cb_add_button_press' => { 'window_handle' => 1, 'widget_name' => 2, 'cb_name' => 3 }, 'widget_cb_add_button_press:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'cb_name' => 'default' }, 'widget_cb_add_button_release' => { 'window_handle' => 1, 'widget_name' => 2, 'cb_name' => 3 }, 'widget_cb_add_button_release:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'cb_name' => 'default' }, 'widget_cb_add_key_press' => { 'window_handle' => 1, 'widget_name' => 2, 'cb_name' => 3 }, 'widget_cb_add_key_press:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'cb_name' => 'default' }, 'widget_cb_add_key_release' => { 'window_handle' => 1, 'widget_name' => 2, 'cb_name' => 3 }, 'widget_cb_add_key_release:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'cb_name' => 'default' }, 'widget_cb_add_pushbutton_push' => { 'window_handle' => 1, 'widget_name' => 2, 'cb_name' => 3 }, 'widget_cb_add_pushbutton_push:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'cb_name' => 'default' }, 'widget_cb_add_slideswitch_slide' => { 'window_handle' => 1, 'widget_name' => 2, 'cb_name' => 3 }, 'widget_cb_add_slideswitch_slide:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'cb_name' => 'default' }, 'widget_cb_add_toggleswitch_toggle' => { 'window_handle' => 1, 'widget_name' => 2, 'cb_name' => 3 }, 'widget_cb_add_toggleswitch_toggle:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'cb_name' => 'default' }, 'widget_cb_add_turnswitch_turn' => { 'window_handle' => 1, 'widget_name' => 2, 'cb_name' => 3 }, 'widget_cb_add_turnswitch_turn:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'cb_name' => 'default' }, 'widget_cb_delete_button_press' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_cb_delete_button_press:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_cb_delete_button_release' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_cb_delete_button_release:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_cb_delete_key_press' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_cb_delete_key_press:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_cb_delete_key_release' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_cb_delete_key_release:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_cb_delete_pushbutton_push' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_cb_delete_pushbutton_push:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_cb_delete_slideswitch_slide' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_cb_delete_slideswitch_slide:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_cb_delete_toggleswitch_toggle' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_cb_delete_toggleswitch_toggle:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_cb_delete_turnswitch_turn' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_cb_delete_turnswitch_turn:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_change_set' => { 'window_handle' => 1, 'widget_set' => 2 }, 'widget_change_set:types' => { 'window_handle' => 'handle', 'widget_set' => 'uint' }, 'widget_create_block' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'size_width' => 5, 'size_height' => 6 }, 'widget_create_block:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'size_width' => 'uint', 'size_height' => 'uint' }, 'widget_create_label' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4 }, 'widget_create_label:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int' }, 'widget_create_lamp' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8 }, 'widget_create_lamp:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint' }, 'widget_create_led_1' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8 }, 'widget_create_led_1:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint' }, 'widget_create_led_2' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8 }, 'widget_create_led_2:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint' }, 'widget_create_led_3' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8 }, 'widget_create_led_3:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint' }, 'widget_create_pushbutton_1' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8, 'sticky' => 9 }, 'widget_create_pushbutton_1:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint', 'sticky' => 'uint' }, 'widget_create_pushbutton_2' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8, 'sticky' => 9 }, 'widget_create_pushbutton_2:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint', 'sticky' => 'uint' }, 'widget_create_pushbutton_3' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8, 'sticky' => 9 }, 'widget_create_pushbutton_3:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint', 'sticky' => 'uint' }, 'widget_create_slideswitch' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8, 'slide_length' => 9, 'step_total' => 10, 'step_start' => 11 }, 'widget_create_slideswitch:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint', 'slide_length' => 'uint', 'step_total' => 'uint', 'step_start' => 'uint' }, 'widget_create_toggleswitch' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8, 'step_total' => 9, 'step_start' => 10 }, 'widget_create_toggleswitch:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint', 'step_total' => 'uint', 'step_start' => 'uint' }, 'widget_create_turnswitch' => { 'window_handle' => 1, 'widget_name' => 2, 'position_x' => 3, 'position_y' => 4, 'title_x_offset' => 5, 'title_y_offset' => 6, 'widget_subtype' => 7, 'title_position' => 8, 'angle_min' => 9, 'angle_max' => 10, 'step_total' => 11, 'step_start' => 12 }, 'widget_create_turnswitch:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'position_x' => 'int', 'position_y' => 'int', 'title_x_offset' => 'int', 'title_y_offset' => 'int', 'widget_subtype' => 'uint', 'title_position' => 'uint', 'angle_min' => 'uint', 'angle_max' => 'uint', 'step_total' => 'uint', 'step_start' => 'uint' }, 'widget_delete' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_delete:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_disable' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_disable:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_enable' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_enable:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_indicator_set' => { 'window_handle' => 1, 'widget_name' => 2, 'font_file' => 3, 'font_charset' => 4, 'font_size' => 5, 'font_resolution' => 6, 'indicator_color' => 7, 'indicator_mode' => 8, 'indicator_vertical_offset' => 9 }, 'widget_indicator_set:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'font_file' => 'default', 'font_charset' => 'default', 'font_size' => 'uint', 'font_resolution' => 'uint', 'indicator_color' => 'color', 'indicator_mode' => 'uint', 'indicator_vertical_offset' => 'int' }, 'widget_refresh' => { 'window_handle' => 1 }, 'widget_refresh:types' => { 'window_handle' => 'handle' }, 'widget_step_get' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_step_get:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_step_get_max' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_step_get_max:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_step_get_min' => { 'window_handle' => 1, 'widget_name' => 2 }, 'widget_step_get_min:types' => { 'window_handle' => 'handle', 'widget_name' => 'default' }, 'widget_step_set' => { 'window_handle' => 1, 'widget_name' => 2, 'step' => 3 }, 'widget_step_set:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'step' => 'uint' }, 'widget_trigger_set' => { 'window_handle' => 1, 'widget_name' => 2, 'trigger' => 3 }, 'widget_trigger_set:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'trigger' => 'uint' }, 'widget_update_border' => { 'window_handle' => 1, 'widget_name' => 2, 'color' => 3, 'thickness' => 4 }, 'widget_update_border:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'color' => 'color', 'thickness' => 'uint' }, 'widget_update_color' => { 'window_handle' => 1, 'widget_name' => 2, 'color' => 3 }, 'widget_update_color:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'color' => 'color' }, 'widget_update_image' => { 'window_handle' => 1, 'widget_name' => 2, 'image_x_offset' => 3, 'image_y_offset' => 4, 'image' => 5 }, 'widget_update_image:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'image_x_offset' => 'int', 'image_y_offset' => 'int', 'image' => 'image' }, 'widget_update_image_file' => { 'window_handle' => 1, 'widget_name' => 2, 'image_file' => 3 }, 'widget_update_image_file:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'image_file' => 'default' }, 'widget_update_label' => { 'window_handle' => 1, 'widget_name' => 2, 'label' => 3, 'label_charset' => 4, 'font_file' => 5, 'font_size' => 6, 'font_resolution' => 7, 'justification' => 8, 'color' => 9 }, 'widget_update_label:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'label' => 'default', 'label_charset' => 'default', 'font_file' => 'default', 'font_size' => 'uint', 'font_resolution' => 'uint', 'justification' => 'uint', 'color' => 'color' }, 'widget_update_scale_bars' => { 'window_handle' => 1, 'widget_name' => 2, 'font_file' => 3, 'font_charset' => 4, 'font_size' => 5, 'font_resolution' => 6, 'start_value' => 7, 'end_value' => 8, 'steps' => 9, 'color' => 10 }, 'widget_update_scale_bars:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'font_file' => 'default', 'font_charset' => 'default', 'font_size' => 'uint', 'font_resolution' => 'uint', 'start_value' => 'f64', 'end_value' => 'f64', 'steps' => 'uint', 'color' => 'color' }, 'widget_update_scale_dots' => { 'window_handle' => 1, 'widget_name' => 2, 'font_file' => 3, 'font_charset' => 4, 'font_size' => 5, 'font_resolution' => 6, 'start_value' => 7, 'end_value' => 8, 'steps' => 9, 'color' => 10 }, 'widget_update_scale_dots:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'font_file' => 'default', 'font_charset' => 'default', 'font_size' => 'uint', 'font_resolution' => 'uint', 'start_value' => 'f64', 'end_value' => 'f64', 'steps' => 'uint', 'color' => 'color' }, 'widget_update_scale_nude' => { 'window_handle' => 1, 'widget_name' => 2, 'font_file' => 3, 'font_charset' => 4, 'font_size' => 5, 'font_resolution' => 6, 'start_value' => 7, 'end_value' => 8, 'steps' => 9, 'color' => 10 }, 'widget_update_scale_nude:types' => { 'window_handle' => 'handle', 'widget_name' => 'default', 'font_file' => 'default', 'font_charset' => 'default', 'font_size' => 'uint', 'font_resolution' => 'uint', 'start_value' => 'f64', 'end_value' => 'f64', 'steps' => 'uint', 'color' => 'color' }, 'window_close' => { 'window_handle' => 1 }, 'window_close:types' => { 'window_handle' => 'handle' }, 'window_icon' => { 'window_handle' => 1, 'file_name' => 2 }, 'window_icon:types' => { 'window_handle' => 'handle', 'file_name' => 'default' }, 'window_init' => { }, 'window_init:types' => { }, 'window_map' => { 'window_handle' => 1 }, 'window_map:types' => { 'window_handle' => 'handle' }, 'window_open' => { 'title_name' => 1, 'title_charset' => 2, 'parent_handle' => 3, 'widget_stack_id' => 4, 'widget_set' => 5, 'window_refresh_divider' => 6, 'position_x' => 7, 'position_y' => 8, 'size_width' => 9, 'size_height' => 10, 'cb_main_loop' => 11, 'cb_expose' => 12, 'cb_key_press' => 13, 'cb_key_release' => 14, 'cb_button_press' => 15, 'cb_button_release' => 16, 'cb_client_message' => 17, 'cb_configure_notify' => 18, 'cb_destroy_notify' => 19, 'cb_motion_notify' => 20, 'cb_map_notify' => 21, 'cb_unmap_notify' => 22, 'cb_open_notify' => 23 }, 'window_open:types' => { 'title_name' => 'default', 'title_charset' => 'default', 'parent_handle' => 'handle', 'widget_stack_id' => 'uint', 'widget_set' => 'uint', 'window_refresh_divider' => 'uint', 'position_x' => 'int', 'position_y' => 'int', 'size_width' => 'uint', 'size_height' => 'uint', 'cb_main_loop' => 'default', 'cb_expose' => 'default', 'cb_key_press' => 'default', 'cb_key_release' => 'default', 'cb_button_press' => 'default', 'cb_button_release' => 'default', 'cb_client_message' => 'default', 'cb_configure_notify' => 'default', 'cb_destroy_notify' => 'default', 'cb_motion_notify' => 'default', 'cb_map_notify' => 'default', 'cb_unmap_notify' => 'default', 'cb_open_notify' => 'default' }, 'window_refresh' => { 'window_handle' => 1, 'area_x' => 2, 'area_y' => 3, 'area_width' => 4, 'area_height' => 5 }, 'window_refresh:types' => { 'window_handle' => 'handle', 'area_x' => 'int', 'area_y' => 'int', 'area_width' => 'uint', 'area_height' => 'uint' }, 'window_set_attrs' => { 'window_handle' => 1, 'attribute' => 2, 'attribute_value' => 3 }, 'window_set_attrs:types' => { 'window_handle' => 'handle', 'attribute' => 'uint', 'attribute_value' => 'f64' }, 'window_unmap' => { 'window_handle' => 1 }, 'window_unmap:types' => { 'window_handle' => 'handle' } ); return %c; } sub pre_inc_macro { my ($arg) = @_; # There 0 is ZERO, as I am too lazy to battle against perl whether 0 # is valid number or undef. ZERO is later translated to 0 when needed. # my @c = ( "; Predefined macros for some font, widget and window functions" . "\n", ";" . "\n", "define SET_OFF (ZERO)" . "\n", "define SET_ON (1)" . "\n", "define DEFAULT_CHARSET ('utf8')" . "\n", "define DEFAULT_RESOLUTION (ZERO)" . "\n", "" . "\n", "; For exit function" . "\n", ";" . "\n", "define NOERROR (ZERO)" . "\n", "define ERROR (1)" . "\n", "" . "\n", "; For some thread functions" . "\n", ";" . "\n", "; param THREAD_NAME:" . "\n", "define DEFAULT_THREAD ('T')" . "\n", "" . "\n", "; For clock_set_multiplier function" . "\n", ";" . "\n", "define CLOCK_REALTIME (1)" . "\n", "" . "\n", "; For some audio functions" . "\n", ";" . "\n", "define VOL_MIN (ZERO)" . "\n", "define VOL_MAX (1)" . "\n", "define PAN_CENTER (ZERO)" . "\n", "define PAN_LEFTMOST (-1)" . "\n", "define PAN_RIGHTMOST (1)" . "\n", "define FREQ_C0 (16.3516)" . "\n", "define FREQ_Db0 (17.32391)" . "\n", "define FREQ_D0 (18.35405)" . "\n", "define FREQ_Eb0 (19.44544)" . "\n", "define FREQ_E0 (20.60172)" . "\n", "define FREQ_F0 (21.82676)" . "\n", "define FREQ_Gb0 (23.12465)" . "\n", "define FREQ_G0 (24.49971)" . "\n", "define FREQ_Ab0 (25.95654)" . "\n", "define FREQ_A0 (27.5)" . "\n", "define FREQ_Bb0 (29.13524)" . "\n", "define FREQ_B0 (30.86771)" . "\n", "define FREQ_C1 (32.70320)" . "\n", "define FREQ_Db1 (34.64783)" . "\n", "define FREQ_D1 (36.70810)" . "\n", "define FREQ_Eb1 (38.89087)" . "\n", "define FREQ_E1 (41.20344)" . "\n", "define FREQ_F1 (43.65353)" . "\n", "define FREQ_Gb1 (46.2493)" . "\n", "define FREQ_G1 (48.99943)" . "\n", "define FREQ_Ab1 (51.91309)" . "\n", "define FREQ_A1 (55.0)" . "\n", "define FREQ_Bb1 (58.27047)" . "\n", "define FREQ_B1 (61.73541)" . "\n", "define FREQ_C2 (65.40639)" . "\n", "define FREQ_Db2 (69.29566)" . "\n", "define FREQ_D2 (73.41619)" . "\n", "define FREQ_Eb2 (77.78175)" . "\n", "define FREQ_E2 (82.40689)" . "\n", "define FREQ_F2 (87.30706)" . "\n", "define FREQ_Gb2 (92.49861)" . "\n", "define FREQ_G2 (97.99886)" . "\n", "define FREQ_Ab2 (103.8262)" . "\n", "define FREQ_A2 (110.0)" . "\n", "define FREQ_Bb2 (116.5409)" . "\n", "define FREQ_B2 (123.4708)" . "\n", "define FREQ_C3 (130.8128)" . "\n", "define FREQ_Db3 (138.5913)" . "\n", "define FREQ_D3 (146.8324)" . "\n", "define FREQ_Eb3 (155.5635)" . "\n", "define FREQ_E3 (164.8138)" . "\n", "define FREQ_F3 (174.6141)" . "\n", "define FREQ_Gb3 (184.9972)" . "\n", "define FREQ_G3 (195.9977)" . "\n", "define FREQ_Ab3 (207.6523)" . "\n", "define FREQ_A3 (220.0)" . "\n", "define FREQ_Bb3 (233.0819)" . "\n", "define FREQ_B3 (246.9417)" . "\n", "define FREQ_C4 (261.6256)" . "\n", "define FREQ_MIDDLE_C (261.6256)" . "\n", "define FREQ_Db4 (277.1826)" . "\n", "define FREQ_D4 (293.6648)" . "\n", "define FREQ_Eb4 (311.1270)" . "\n", "define FREQ_E4 (329.6276)" . "\n", "define FREQ_F4 (349.2282)" . "\n", "define FREQ_Gb4 (369.9944)" . "\n", "define FREQ_G4 (391.9954)" . "\n", "define FREQ_Ab4 (415.3047)" . "\n", "define FREQ_A4 (440.0)" . "\n", "define FREQ_Bb4 (466.1638)" . "\n", "define FREQ_B4 (493.8833)" . "\n", "define FREQ_C5 (523.2511)" . "\n", "define FREQ_Db5 (554.3653)" . "\n", "define FREQ_D5 (587.3295)" . "\n", "define FREQ_Eb5 (622.254)" . "\n", "define FREQ_E5 (659.2551)" . "\n", "define FREQ_F5 (698.4565)" . "\n", "define FREQ_Gb5 (739.9888)" . "\n", "define FREQ_G5 (783.9909)" . "\n", "define FREQ_Ab5 (830.6094)" . "\n", "define FREQ_A5 (880.0)" . "\n", "define FREQ_Bb5 (932.3275)" . "\n", "define FREQ_B5 (987.7666)" . "\n", "define FREQ_C6 (1046.502)" . "\n", "define FREQ_Db6 (1108.731)" . "\n", "define FREQ_D6 (1174.659)" . "\n", "define FREQ_Eb6 (1244.508)" . "\n", "define FREQ_E6 (1318.51)" . "\n", "define FREQ_F6 (1396.913)" . "\n", "define FREQ_Gb6 (1479.978)" . "\n", "define FREQ_G6 (1567.982)" . "\n", "define FREQ_Ab6 (1661.219)" . "\n", "define FREQ_A6 (1760.0)" . "\n", "define FREQ_Bb6 (1864.655)" . "\n", "define FREQ_B6 (1975.533)" . "\n", "define FREQ_C7 (2093.005)" . "\n", "define FREQ_Db7 (2217.461)" . "\n", "define FREQ_D7 (2349.318)" . "\n", "define FREQ_Eb7 (2489.016)" . "\n", "define FREQ_E7 (2637.02)" . "\n", "define FREQ_F7 (2793.826)" . "\n", "define FREQ_Gb7 (2959.955)" . "\n", "define FREQ_G7 (3135.963)" . "\n", "define FREQ_Ab7 (3322.438)" . "\n", "define FREQ_A7 (3520.0)" . "\n", "define FREQ_Bb7 (3729.31)" . "\n", "define FREQ_B7 (3951.066)" . "\n", "define FREQ_C8 (4186.009)" . "\n", "define FREQ_Db8 (4434.922)" . "\n", "define FREQ_D8 (4698.636)" . "\n", "define FREQ_Eb8 (4978.032)" . "\n", "define FREQ_E8 (5274.041)" . "\n", "define FREQ_F8 (5587.652)" . "\n", "define FREQ_Gb8 (5919.911)" . "\n", "define FREQ_G8 (6271.927)" . "\n", "define FREQ_Ab8 (6644.875)" . "\n", "define FREQ_A8 (7040.0)" . "\n", "define FREQ_Bb8 (7458.62)" . "\n", "define FREQ_B8 (7902.133)" . "\n", "" . "\n", "; For some bob functions" . "\n", ";" . "\n", "define MAPPED_HIDDEN (ZERO)" . "\n", "define MAPPED_VISIBLE (1)" . "\n", "define PLAY_DIRECTION_NONE (ZERO)" . "\n", "define PLAY_DIRECTION_FORWARD (1)" . "\n", "define PLAY_DIRECTION_BACKWARDS (2)" . "\n", "define PLAY_MODE_MANUAL (ZERO)" . "\n", "define PLAY_MODE_ONCE (1)" . "\n", "define PLAY_MODE_LOOP (2)" . "\n", "define UPDATE_RATE_DEFAULT (1.0)" . "\n", "" . "\n", "; For widget_indicator_set function" . "\n", ";" . "\n", "; param INDICATOR_MODE:" . "\n", "define INDICATOR_DISABLED (ZERO)" . "\n", "define INDICATOR_ALWAYS (1)" . "\n", "define INDICATOR_ONHOVER (2)" . "\n", "" . "\n", "; For some widget functions" . "\n", ";" . "\n", "define DEFAULT_JUSTIFIED (ZERO)" . "\n", "define LEFT_JUSTIFIED (1)" . "\n", "define RIGHT_JUSTIFIED (2)" . "\n", "define CENTER_JUSTIFIED (3)" . "\n", "define TITLE_DEFAULT (ZERO)" . "\n", "define TITLE_ABOVE (1)" . "\n", "define TITLE_BELOW (2)" . "\n", "define TITLE_LEFT (3)" . "\n", "define TITLE_RIGHT (4)" . "\n", "define ONRELEASE (ZERO)" . "\n", "define ONMOVE (1)" . "\n", "define LAMP_RED (ZERO)" . "\n", "define LAMP_ORANGE (1)" . "\n", "define LAMP_WHITE (2)" . "\n", "define LAMP_GREEN (3)" . "\n", "define LAMP_BLUE (4)" . "\n", "define LAMP_PURPLE (5)" . "\n", "define BUTTON_RED (ZERO)" . "\n", "define BUTTON_YELLOW (1)" . "\n", "define BUTTON_WHITE (2)" . "\n", "define BUTTON_GREEN (3)" . "\n", "define BUTTON_BLUE (4)" . "\n", "define BUTTON_PURPLE (5)" . "\n", "define BUTTON_NOSTICKY (ZERO)" . "\n", "define BUTTON_STICKY (1)" . "\n", "define SLIDER_HORIZ_SLIDER (ZERO)" . "\n", "define SLIDER_VERT_SLIDER (1)" . "\n", "define SLIDER_HORIZ_THIN (2)" . "\n", "define SLIDER_VERT_THIN (3)" . "\n", "define SLIDER_HORIZ_OVAL (4)" . "\n", "define SLIDER_VERT_OVAL (5)" . "\n", "define KNOB_LARGE_CHICKEN (ZERO)" . "\n", "define KNOB_SMALL_CHICKEN (1)" . "\n", "define KNOB_LARGE_FLAT (2)" . "\n", "define KNOB_SMALL_FLAT (3)" . "\n", "define KNOB_LARGE_ROUND (4)" . "\n", "define KNOB_SMALL_ROUND (5)" . "\n", "define STATE_DISABLE (ZERO)" . "\n", "define STATE_ENABLE (1)" . "\n", "" . "\n", "; For window_open function" . "\n", ";" . "\n", "; param PARENT_HANDLE:" . "\n", "define NOPARENT (@0)" . "\n", "; param WIDGET_STACK_ID and WINDOW_SET:" . "\n", "define NOWIDGET (ZERO)" . "\n", "; param WINDOW_REFRESH_DIVIDER:" . "\n", "define PASSIVE_REFRESH (ZERO)" . "\n", "define ACTIVE_REFRESH (1)" . "\n", "; param WINDOW_POSITION_X/Y:" . "\n", "define POS_CENTERED (-1)" . "\n", "" . "\n", "; For window_set_attrs function" . "\n", ";" . "\n", "; param ATTRIBUTE:" . "\n", "define ALWAYS_ABOVE (1)" . "\n", "define ALWAYS_BELOW (2)" . "\n", "define SET_BORDER (3)" . "\n", "define SET_DESKTOP (4)" . "\n", "define SET_X (5)" . "\n", "define SET_Y (6)" . "\n", "define SET_PAGER (7)" . "\n", "define SET_TASKBAR (8)" . "\n", "define SET_STICKY (9)" . "\n", "define SET_TRANSPARENT (10)" . "\n", "\n" ); return @c; }