From 88a4108bde4d02cccd632048b45458e84bc8b40b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 2 Aug 2010 13:34:33 +0000 Subject: [PATCH] PR 11855 * script.cc (Script_options::Script_options): Initialize symbol_definitions_ and symbol_references_. (Script_options::add_symbol_assignment): Update symbol_definitions_ and symbol_references_. (Script_options::add_symbol_reference): New function. (script_symbol): New function. * script.h (class Script_options): Add symbol_definitions_ and symbol_references_ fields. (Script_options::referenced_const_iterator): New type. (Script_options::referenced_begin): New function. (Script_options::referenced_end): New function. (Script_options::is_referenced): New function. (Script_options::any_unreferenced): New function. * script-c.h (script_symbol): Declare. * yyscript.y (exp): Call script_symbol. * symtab.cc: Include "script.h". (Symbol_table::gc_mark_undef_symbols): Add layout parameter. Change all callers. Check symbols referenced by scripts. (Symbol_table::add_undefined_symbols_from_command_line): Add layout parameter. Change all callers. (Symbol_table::do_add_undefined_symbols_from_command_line): Likewise. Break out loop body. Check symbols referenced by scripts. (Symbol_table::add_undefined_symbol_from_command_line): New function broken out of do_add_undefined_symbols_from_command_line. * symtab.h (class Symbol_table): Update declarations. * archive.cc: Include "layout.h". (Archive::should_include_member): Add layout parameter. Change all callers. Check for symbol mentioned in expression. * archive.h (class Archive): Update declaration. * object.cc (Sized_relobj::do_should_include_member): Add layout parameter. * object.h (Object::should_include_member): Add layout parameter. Change all callers. (Object::do_should_include_member): Add layout parameter. (class Sized_relobj): Update declaration. * dynobj.cc (Sized_dynobj::do_should_include_member): Add layout parameter. * dynobj.h (class Sized_dynobj): Update declaration. * plugin.cc (Sized_pluginobj::do_should_include_member): Add layout parameter. * plugin.h (class Sized_pluginobj): Update declaration. --- gold/ChangeLog | 47 +++++++++++++++++++++++ gold/archive.cc | 26 +++++++++---- gold/archive.h | 2 +- gold/dynobj.cc | 6 ++- gold/dynobj.h | 2 +- gold/gold.cc | 4 +- gold/object.cc | 5 ++- gold/object.h | 10 ++--- gold/plugin.cc | 26 ++++++++----- gold/plugin.h | 2 +- gold/script-c.h | 8 ++++ gold/script.cc | 35 ++++++++++++++++- gold/script.h | 34 +++++++++++++++++ gold/symtab.cc | 99 ++++++++++++++++++++++++++++++++----------------- gold/symtab.h | 11 ++++-- gold/yyscript.y | 2 +- 16 files changed, 249 insertions(+), 70 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 97f7977495a..b08fcdfb59f 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,50 @@ +2010-08-02 Ian Lance Taylor + + PR 11855 + * script.cc (Script_options::Script_options): Initialize + symbol_definitions_ and symbol_references_. + (Script_options::add_symbol_assignment): Update + symbol_definitions_ and symbol_references_. + (Script_options::add_symbol_reference): New function. + (script_symbol): New function. + * script.h (class Script_options): Add symbol_definitions_ and + symbol_references_ fields. + (Script_options::referenced_const_iterator): New type. + (Script_options::referenced_begin): New function. + (Script_options::referenced_end): New function. + (Script_options::is_referenced): New function. + (Script_options::any_unreferenced): New function. + * script-c.h (script_symbol): Declare. + * yyscript.y (exp): Call script_symbol. + * symtab.cc: Include "script.h". + (Symbol_table::gc_mark_undef_symbols): Add layout parameter. + Change all callers. Check symbols referenced by scripts. + (Symbol_table::add_undefined_symbols_from_command_line): Add + layout parameter. Change all callers. + (Symbol_table::do_add_undefined_symbols_from_command_line): + Likewise. Break out loop body. Check symbols referenced by + scripts. + (Symbol_table::add_undefined_symbol_from_command_line): New + function broken out of + do_add_undefined_symbols_from_command_line. + * symtab.h (class Symbol_table): Update declarations. + * archive.cc: Include "layout.h". + (Archive::should_include_member): Add layout parameter. Change + all callers. Check for symbol mentioned in expression. + * archive.h (class Archive): Update declaration. + * object.cc (Sized_relobj::do_should_include_member): Add layout + parameter. + * object.h (Object::should_include_member): Add layout parameter. + Change all callers. + (Object::do_should_include_member): Add layout parameter. + (class Sized_relobj): Update declaration. + * dynobj.cc (Sized_dynobj::do_should_include_member): Add layout + parameter. + * dynobj.h (class Sized_dynobj): Update declaration. + * plugin.cc (Sized_pluginobj::do_should_include_member): Add + layout parameter. + * plugin.h (class Sized_pluginobj): Update declaration. + 2010-08-02 Ian Lance Taylor PR 11866 diff --git a/gold/archive.cc b/gold/archive.cc index 202fc2c8eb3..f1000a195de 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -36,6 +36,7 @@ #include "readsyms.h" #include "symtab.h" #include "object.h" +#include "layout.h" #include "archive.h" #include "plugin.h" @@ -603,8 +604,9 @@ Archive::read_symbols(off_t off) } Archive::Should_include -Archive::should_include_member(Symbol_table* symtab, const char* sym_name, - Symbol** symp, std::string* why, char** tmpbufp, +Archive::should_include_member(Symbol_table* symtab, Layout* layout, + const char* sym_name, Symbol** symp, + std::string* why, char** tmpbufp, size_t* tmpbuflen) { // In an object file, and therefore in an archive map, an @@ -648,13 +650,22 @@ Archive::should_include_member(Symbol_table* symtab, const char* sym_name, if (sym == NULL) { // Check whether the symbol was named in a -u option. - if (!parameters->options().is_undefined(sym_name)) - return Archive::SHOULD_INCLUDE_UNKNOWN; - else + if (parameters->options().is_undefined(sym_name)) { *why = "-u "; *why += sym_name; } + else if (layout->script_options()->is_referenced(sym_name)) + { + size_t alc = 100 + strlen(sym_name); + char* buf = new char[alc]; + snprintf(buf, alc, _("script or expression reference to %s"), + sym_name); + *why = buf; + delete[] buf; + } + else + return Archive::SHOULD_INCLUDE_UNKNOWN; } else if (!sym->is_undefined()) return Archive::SHOULD_INCLUDE_NO; @@ -726,8 +737,8 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, Symbol* sym; std::string why; Archive::Should_include t = - Archive::should_include_member(symtab, sym_name, &sym, &why, - &tmpbuf, &tmpbuflen); + Archive::should_include_member(symtab, layout, sym_name, &sym, + &why, &tmpbuf, &tmpbuflen); if (t == Archive::SHOULD_INCLUDE_NO || t == Archive::SHOULD_INCLUDE_YES) @@ -1015,6 +1026,7 @@ Lib_group::add_symbols(Symbol_table* symtab, Layout* layout, && (member.sd_ == NULL || member.sd_->symbol_names != NULL)) { Archive::Should_include t = obj->should_include_member(symtab, + layout, member.sd_, &why); diff --git a/gold/archive.h b/gold/archive.h index a2d2af485e0..bff34576eca 100644 --- a/gold/archive.h +++ b/gold/archive.h @@ -176,7 +176,7 @@ class Archive }; static Should_include - should_include_member(Symbol_table* symtab, const char* sym_name, + should_include_member(Symbol_table* symtab, Layout*, const char* sym_name, Symbol** symp, std::string* why, char** tmpbufp, size_t* tmpbuflen); diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 81bc085b46a..e4a976dcba0 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -753,8 +753,10 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, template Archive::Should_include -Sized_dynobj::do_should_include_member( - Symbol_table*, Read_symbols_data*, std::string*) +Sized_dynobj::do_should_include_member(Symbol_table*, + Layout*, + Read_symbols_data*, + std::string*) { return Archive::SHOULD_INCLUDE_YES; } diff --git a/gold/dynobj.h b/gold/dynobj.h index 08cf78db725..8787adaab60 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -178,7 +178,7 @@ class Sized_dynobj : public Dynobj do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include - do_should_include_member(Symbol_table* symtab, Read_symbols_data*, + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, std::string* why); // Get the size of a section. diff --git a/gold/gold.cc b/gold/gold.cc index ba02db2f1bf..541d177be55 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -309,7 +309,7 @@ queue_middle_tasks(const General_options& options, Mapfile* mapfile) { // Add any symbols named with -u options to the symbol table. - symtab->add_undefined_symbols_from_command_line(); + symtab->add_undefined_symbols_from_command_line(layout); // If garbage collection was chosen, relocs have been read and processed // at this point by pre_middle_tasks. Layout can then be done for all @@ -333,7 +333,7 @@ queue_middle_tasks(const General_options& options, } } // Symbols named with -u should not be considered garbage. - symtab->gc_mark_undef_symbols(); + symtab->gc_mark_undef_symbols(layout); gold_assert(symtab->gc() != NULL); // Do a transitive closure on all references to determine the worklist. symtab->gc()->do_transitive_closure(); diff --git a/gold/object.cc b/gold/object.cc index ed87b1aef14..1bf73677f62 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -1614,6 +1614,7 @@ Sized_relobj::do_add_symbols(Symbol_table* symtab, template Archive::Should_include Sized_relobj::do_should_include_member(Symbol_table* symtab, + Layout* layout, Read_symbols_data* sd, std::string* why) { @@ -1639,7 +1640,9 @@ Sized_relobj::do_should_include_member(Symbol_table* symtab, unsigned int st_name = sym.get_st_name(); const char* name = sym_names + st_name; Symbol* symbol; - Archive::Should_include t = Archive::should_include_member(symtab, name, + Archive::Should_include t = Archive::should_include_member(symtab, + layout, + name, &symbol, why, &tmpbuf, &tmpbuflen); diff --git a/gold/object.h b/gold/object.h index f60d90972e7..59b723fab40 100644 --- a/gold/object.h +++ b/gold/object.h @@ -405,9 +405,9 @@ class Object // Add symbol information to the global symbol table. Archive::Should_include - should_include_member(Symbol_table* symtab, Read_symbols_data* sd, - std::string* why) - { return this->do_should_include_member(symtab, sd, why); } + should_include_member(Symbol_table* symtab, Layout* layout, + Read_symbols_data* sd, std::string* why) + { return this->do_should_include_member(symtab, layout, sd, why); } // Functions and types for the elfcpp::Elf_file interface. This // permit us to use Object as the File template parameter for @@ -546,7 +546,7 @@ class Object do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*) = 0; virtual Archive::Should_include - do_should_include_member(Symbol_table* symtab, Read_symbols_data*, + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, std::string* why) = 0; // Return the location of the contents of a section. Implemented by @@ -1623,7 +1623,7 @@ class Sized_relobj : public Relobj do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include - do_should_include_member(Symbol_table* symtab, Read_symbols_data*, + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, std::string* why); // Read the relocs. diff --git a/gold/plugin.cc b/gold/plugin.cc index 76b24314c46..1c86c03b422 100644 --- a/gold/plugin.cc +++ b/gold/plugin.cc @@ -705,26 +705,32 @@ Sized_pluginobj::do_add_symbols(Symbol_table* symtab, template Archive::Should_include Sized_pluginobj::do_should_include_member( - Symbol_table* symtab, Read_symbols_data*, std::string* why) + Symbol_table* symtab, + Layout* layout, + Read_symbols_data*, + std::string* why) { char* tmpbuf = NULL; size_t tmpbuflen = 0; - for (int i = 0; i < this->nsyms_; ++i) { - const struct ld_plugin_symbol& sym = this->syms_[i]; - const char* name = sym.name; - Symbol* symbol; - Archive::Should_include t = Archive::should_include_member(symtab, name, - &symbol, why, - &tmpbuf, - &tmpbuflen); + for (int i = 0; i < this->nsyms_; ++i) + { + const struct ld_plugin_symbol& sym = this->syms_[i]; + const char* name = sym.name; + Symbol* symbol; + Archive::Should_include t = Archive::should_include_member(symtab, + layout, + name, + &symbol, why, + &tmpbuf, + &tmpbuflen); if (t == Archive::SHOULD_INCLUDE_YES) { if (tmpbuf != NULL) free(tmpbuf); return t; } - } + } if (tmpbuf != NULL) free(tmpbuf); return Archive::SHOULD_INCLUDE_UNKNOWN; diff --git a/gold/plugin.h b/gold/plugin.h index 81c3be6508b..47e634e7a12 100644 --- a/gold/plugin.h +++ b/gold/plugin.h @@ -376,7 +376,7 @@ class Sized_pluginobj : public Pluginobj do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); Archive::Should_include - do_should_include_member(Symbol_table* symtab, Read_symbols_data*, + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, std::string* why); // Get the size of a section. diff --git a/gold/script-c.h b/gold/script-c.h index 29901e3c3a8..1f79eacdd99 100644 --- a/gold/script-c.h +++ b/gold/script-c.h @@ -303,6 +303,14 @@ script_push_lex_into_version_mode(void* closure); extern void script_pop_lex_mode(void* closure); +/* Called by the bison parser to get the value of a symbol. This is + called for a reference to a symbol, but is not called for something + like "sym += 10". Uses of the special symbol "." can just call + script_exp_string. */ + +extern Expression_ptr +script_symbol(void* closure, const char*, size_t); + /* Called by the bison parser to set a symbol to a value. PROVIDE is non-zero if the symbol should be provided--only defined if there is an undefined reference. HIDDEN is non-zero if the symbol should be diff --git a/gold/script.cc b/gold/script.cc index 2cdaae6384e..e0b9359abdc 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -1045,8 +1045,8 @@ Script_assertion::print(FILE* f) const // Class Script_options. Script_options::Script_options() - : entry_(), symbol_assignments_(), version_script_info_(), - script_sections_() + : entry_(), symbol_assignments_(), symbol_definitions_(), + symbol_references_(), version_script_info_(), script_sections_() { } @@ -1071,6 +1071,13 @@ Script_options::add_symbol_assignment(const char* name, size_t length, value, provide, hidden); this->symbol_assignments_.push_back(p); } + + if (!provide) + { + std::string n(name, length); + this->symbol_definitions_.insert(n); + this->symbol_references_.erase(n); + } } else { @@ -1084,6 +1091,19 @@ Script_options::add_symbol_assignment(const char* name, size_t length, } } +// Add a reference to a symbol. + +void +Script_options::add_symbol_reference(const char* name, size_t length) +{ + if (length != 1 || name[0] != '.') + { + std::string n(name, length); + if (this->symbol_definitions_.find(n) == this->symbol_definitions_.end()) + this->symbol_references_.insert(n); + } +} + // Add an assertion. void @@ -2679,6 +2699,17 @@ script_set_common_allocation(void* closurev, int set) script_parse_option(closurev, arg, strlen(arg)); } +// Called by the bison parser to refer to a symbol. + +extern "C" Expression* +script_symbol(void *closurev, const char* name, size_t length) +{ + Parser_closure* closure = static_cast(closurev); + if (length != 1 || name[0] != '.') + closure->script_options()->add_symbol_reference(name, length); + return script_exp_string(name, length); +} + // Called by the bison parser to define a symbol. extern "C" void diff --git a/gold/script.h b/gold/script.h index 3b8cb92f1c8..70e3a59e7b4 100644 --- a/gold/script.h +++ b/gold/script.h @@ -423,6 +423,10 @@ class Script_options add_symbol_assignment(const char* name, size_t length, bool is_defsym, Expression* value, bool provide, bool hidden); + // Add a reference to a symbol. + void + add_symbol_reference(const char* name, size_t length); + // Add an assertion. void add_assertion(Expression* check, const char* message, size_t messagelen); @@ -439,6 +443,32 @@ class Script_options void add_symbols_to_table(Symbol_table*); + // Used to iterate over symbols which are referenced in expressions + // but not defined. + typedef Unordered_set::const_iterator referenced_const_iterator; + + referenced_const_iterator + referenced_begin() const + { return this->symbol_references_.begin(); } + + referenced_const_iterator + referenced_end() const + { return this->symbol_references_.end(); } + + // Return whether a symbol is referenced but not defined. + bool + is_referenced(const std::string& name) const + { + return (this->symbol_references_.find(name) + != this->symbol_references_.end()); + } + + // Return whether there are any symbols which were referenced but + // not defined. + bool + any_unreferenced() const + { return !this->symbol_references_.empty(); } + // Finalize the symbol values. Also check assertions. void finalize_symbols(Symbol_table*, const Layout*); @@ -497,6 +527,10 @@ class Script_options std::string entry_; // Symbols to set. Symbol_assignments symbol_assignments_; + // Symbols defined in an expression, for faster lookup. + Unordered_set symbol_definitions_; + // Symbols referenced in an expression. + Unordered_set symbol_references_; // Assertions to check. Assertions assertions_; // Version information parsed from a version script. diff --git a/gold/symtab.cc b/gold/symtab.cc index a29e6adeda9..f46d8deb75a 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -38,7 +38,7 @@ #include "target.h" #include "workqueue.h" #include "symtab.h" -#include "demangle.h" // needed for --dynamic-list-cpp-new +#include "script.h" #include "plugin.h" namespace gold @@ -530,7 +530,7 @@ Symbol_table::is_section_folded(Object* obj, unsigned int shndx) const // work list to avoid gc'ing them. void -Symbol_table::gc_mark_undef_symbols() +Symbol_table::gc_mark_undef_symbols(Layout* layout) { for (options::String_set::const_iterator p = parameters->options().undefined_begin(); @@ -553,6 +553,27 @@ Symbol_table::gc_mark_undef_symbols() } } } + + for (Script_options::referenced_const_iterator p = + layout->script_options()->referenced_begin(); + p != layout->script_options()->referenced_end(); + ++p) + { + Symbol* sym = this->lookup(p->c_str()); + gold_assert(sym != NULL); + if (sym->source() == Symbol::FROM_OBJECT + && !sym->object()->is_dynamic()) + { + Relobj* obj = static_cast(sym->object()); + bool is_ordinary; + unsigned int shndx = sym->shndx(&is_ordinary); + if (is_ordinary) + { + gold_assert(this->gc_ != NULL); + this->gc_->worklist().push(Section_id(obj, shndx)); + } + } + } } void @@ -2163,14 +2184,15 @@ Symbol_table::get_copy_source(const Symbol* sym) const // Add any undefined symbols named on the command line. void -Symbol_table::add_undefined_symbols_from_command_line() +Symbol_table::add_undefined_symbols_from_command_line(Layout* layout) { - if (parameters->options().any_undefined()) + if (parameters->options().any_undefined() + || layout->script_options()->any_unreferenced()) { if (parameters->target().get_size() == 32) { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) - this->do_add_undefined_symbols_from_command_line<32>(); + this->do_add_undefined_symbols_from_command_line<32>(layout); #else gold_unreachable(); #endif @@ -2178,7 +2200,7 @@ Symbol_table::add_undefined_symbols_from_command_line() else if (parameters->target().get_size() == 64) { #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) - this->do_add_undefined_symbols_from_command_line<64>(); + this->do_add_undefined_symbols_from_command_line<64>(layout); #else gold_unreachable(); #endif @@ -2190,50 +2212,59 @@ Symbol_table::add_undefined_symbols_from_command_line() template void -Symbol_table::do_add_undefined_symbols_from_command_line() +Symbol_table::do_add_undefined_symbols_from_command_line(Layout* layout) { for (options::String_set::const_iterator p = parameters->options().undefined_begin(); p != parameters->options().undefined_end(); ++p) - { - const char* name = p->c_str(); + this->add_undefined_symbol_from_command_line(p->c_str()); - if (this->lookup(name) != NULL) - continue; + for (Script_options::referenced_const_iterator p = + layout->script_options()->referenced_begin(); + p != layout->script_options()->referenced_end(); + ++p) + this->add_undefined_symbol_from_command_line(p->c_str()); +} + +template +void +Symbol_table::add_undefined_symbol_from_command_line(const char* name) +{ + if (this->lookup(name) != NULL) + return; - const char* version = NULL; + const char* version = NULL; - Sized_symbol* sym; - Sized_symbol* oldsym; - bool resolve_oldsym; - if (parameters->target().is_big_endian()) - { + Sized_symbol* sym; + Sized_symbol* oldsym; + bool resolve_oldsym; + if (parameters->target().is_big_endian()) + { #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) - sym = this->define_special_symbol(&name, &version, - false, &oldsym, - &resolve_oldsym); + sym = this->define_special_symbol(&name, &version, + false, &oldsym, + &resolve_oldsym); #else - gold_unreachable(); + gold_unreachable(); #endif - } - else - { + } + else + { #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) - sym = this->define_special_symbol(&name, &version, - false, &oldsym, - &resolve_oldsym); + sym = this->define_special_symbol(&name, &version, + false, &oldsym, + &resolve_oldsym); #else - gold_unreachable(); + gold_unreachable(); #endif - } + } - gold_assert(oldsym == NULL); + gold_assert(oldsym == NULL); - sym->init_undefined(name, version, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, - elfcpp::STV_DEFAULT, 0); - ++this->saw_undefined_; - } + sym->init_undefined(name, version, elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, + elfcpp::STV_DEFAULT, 0); + ++this->saw_undefined_; } // Set the dynamic symbol indexes. INDEX is the index of the first diff --git a/gold/symtab.h b/gold/symtab.h index 3058546c7eb..8178e2c6053 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -1269,7 +1269,7 @@ class Symbol_table // During garbage collection, this keeps undefined symbols. void - gc_mark_undef_symbols(); + gc_mark_undef_symbols(Layout*); // During garbage collection, this ensures externally visible symbols // are not treated as garbage while building shared objects. @@ -1419,7 +1419,7 @@ class Symbol_table // Add any undefined symbols named on the command line to the symbol // table. void - add_undefined_symbols_from_command_line(); + add_undefined_symbols_from_command_line(Layout*); // SYM is defined using a COPY reloc. Return the dynamic object // where the original definition was found. @@ -1633,7 +1633,12 @@ class Symbol_table // table, sized version. template void - do_add_undefined_symbols_from_command_line(); + do_add_undefined_symbols_from_command_line(Layout*); + + // Add one undefined symbol. + template + void + add_undefined_symbol_from_command_line(const char* name); // Types of common symbols. diff --git a/gold/yyscript.y b/gold/yyscript.y index 9cd29fb4705..203deb7cbf8 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -867,7 +867,7 @@ exp: | INTEGER { $$ = script_exp_integer($1); } | string - { $$ = script_exp_string($1.value, $1.length); } + { $$ = script_symbol(closure, $1.value, $1.length); } | MAX_K '(' exp ',' exp ')' { $$ = script_exp_function_max($3, $5); } | MIN_K '(' exp ',' exp ')' -- 2.30.2