From d6d50b7b4e8a5cc0cb66ea2a55b62abc72e18b7f Mon Sep 17 00:00:00 2001 From: kyawaway Date: Tue, 18 Jun 2024 13:58:15 +0900 Subject: [PATCH] module mell --- lib/mell.lmn | 40 ++++++ src/Makefile.am | 1 + src/ext/init_exts.cpp | 2 + src/ext/mell.cpp | 307 ++++++++++++++++++++++++++++++++++++++++++ src/vm/task.cpp | 79 +++++++++++ 5 files changed, 429 insertions(+) create mode 100644 lib/mell.lmn create mode 100644 src/ext/mell.cpp diff --git a/lib/mell.lmn b/lib/mell.lmn new file mode 100644 index 000000000..b4f0e3b39 --- /dev/null +++ b/lib/mell.lmn @@ -0,0 +1,40 @@ + +{ +module(mell). + +//R=mell.copy(M) :- R=mell.copy(M, copied). + +/** + * mell.copy(+Mem, +CopyTagAtom, -Res): + * + * 与えられた膜を複製する.複製された膜のMem以外の自由リンクは + * それぞれ、指定されたunaryアトムと同名の三引数アトムの複製に接続される. + * @param +Mem 複製する膜 + * @param +CopyTagAtom 複製された膜の自由リンクに接続される三引数アトムと同名のunaryアトム + * @param -Res 結果( 成功時 copied(Mem, Mem_copied, Res) 失敗時 copy_error(Mem, Res) ) + * @example + * R=mell.copy(M, cpd), {$p[M|*Z]} + * ==> + * R=copied(M,M'), {$p[M|*Z]}, {$p[M'|*Z']}, cpd(*Z') + */ +mell.copy(M,A1,A2,A3,B1,B2,C1,C2) :- + '$callback'('mell_copy', M, A1, A2, A3, B1, B2, C1, C2). + + +mell.kill({$p,@p}), :- mell.kill({$p,@p}, X), {killed(X)}. + +/** + * mell.kill(+Mem, +KillTagProc) + * + * 与えられた膜を破棄する.その膜のMem以外の自由リンクにはそれぞれ、 + * 指定されたunaryアトムの複製が接続される. + * ( Memが子膜へのリンクでない場合,Memにkill_error/1が接続される.) + * @param +Mem 破棄する膜 + * @param +KillTagProc 破棄された膜の自由リンクに接続されるプロセス文脈 + * @example mell.kill(M, kld),{$p[M|*Z]} ==> kld(*Z) + */ +//mell.kill(M, T) :- unary(T) | '$callback'('mell_kill', M, T). +mell.kill(M, T) :- '$callback'('mell_kill', M, T). + +}. + diff --git a/src/Makefile.am b/src/Makefile.am index 908212bae..8957a7ef4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,6 +71,7 @@ slim_SOURCES = \ ext/integer.cpp \ ext/float.cpp \ ext/nlmem.cpp \ + ext/mell.cpp \ ext/array.cpp ext/array.h \ ext/atom.cpp \ ext/react_rule.cpp \ diff --git a/src/ext/init_exts.cpp b/src/ext/init_exts.cpp index bf46ddd42..ec2cc42db 100644 --- a/src/ext/init_exts.cpp +++ b/src/ext/init_exts.cpp @@ -45,6 +45,7 @@ void init_integer(void); void init_float(void); void init_nlmem(void); +void init_mell(void); void init_initial_ruleset(void); void init_nd_conf(void); void init_time(void); @@ -58,6 +59,7 @@ void init_builtin_extensions(void) init_integer(); init_float(); init_nlmem(); + init_mell(); init_initial_ruleset(); init_nd_conf(); init_time(); diff --git a/src/ext/mell.cpp b/src/ext/mell.cpp new file mode 100644 index 000000000..c9cfcfd2b --- /dev/null +++ b/src/ext/mell.cpp @@ -0,0 +1,307 @@ +/* + * mell.c - Nonlinear-Membrane + * + * Copyright (c) 2008, Ueda Laboratory LMNtal Group + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of the Ueda Laboratory LMNtal Group nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ + */ + +#include "../lmntal.h" +#include "element/element.h" +#include "verifier/verifier.h" +#include "vm/vm.h" + +void mell_copy(LmnReactCxtRef rc, LmnMembraneRef mem, + LmnAtomRef a0, LmnLinkAttr t0, + LmnAtomRef a1, LmnLinkAttr t1, + LmnAtomRef a2, LmnLinkAttr t2, + LmnAtomRef a3, LmnLinkAttr t3, + LmnAtomRef a4, LmnLinkAttr t4, + LmnAtomRef a5, LmnLinkAttr t5, + LmnAtomRef a6, LmnLinkAttr t6, + LmnAtomRef a7, LmnLinkAttr t7 + ) { + + // copy対象の膜 + LmnSymbolAtomRef org_port_in; + LmnMembraneRef org_mem, trg_mem; + ProcessTableRef atom_map; + org_port_in = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a0)->get_link(0)); + org_mem = LMN_PROXY_GET_MEM(org_port_in); + trg_mem = new LmnMembrane(); + atom_map = lmn_mem_copy_cells(trg_mem, org_mem); + mem->add_child_mem(trg_mem); + + // contractionの膜 + LmnSymbolAtomRef cont_in0, cont_in1, cont_in2; + LmnMembraneRef cont_mem; + cont_in0 = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a1)->get_link(0)); + cont_in1 = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a2)->get_link(0)); + cont_in2 = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a3)->get_link(0)); + cont_mem = LMN_PROXY_GET_MEM(cont_in0); + if(LMN_PROXY_GET_MEM(cont_in1) != LMN_PROXY_GET_MEM(cont_in1) || + LMN_PROXY_GET_MEM(cont_in1) != LMN_PROXY_GET_MEM(cont_in2)) { + fprintf(stderr, "mell.C, mell_copy: illegal argumetns in cont mem\n"); + return; + } + + // cutの膜 + LmnSymbolAtomRef cut_in_port, cut_in_free; + LmnMembraneRef cut_mem; + cut_in_port = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a4)->get_link(0)); + cut_in_free = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a5)->get_link(0)); + cut_mem = LMN_PROXY_GET_MEM(cut_in_port); + if(LMN_PROXY_GET_MEM(cut_in_port) != LMN_PROXY_GET_MEM(cut_in_free)) { + fprintf(stderr, "mell.C, mell_copy: illegal argumetns in cut mem\n"); + return; + } + + // 自由リンク + LmnSymbolAtomRef free0, free1; + free0 = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a6)); + free1 = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a7)); + + { + AtomListEntryRef ent = org_mem->get_atomlist(LMN_IN_PROXY_FUNCTOR); + + if (ent) { + LmnSymbolAtomRef org_in, org_out, trg_in, trg_out; + LmnSymbolAtomRef org_port_out, trg_port_in, trg_port_out; + LmnWord t = 0; + + EACH_ATOM(org_in, ent, ({ + + if (org_in == org_port_in) { + LmnSymbolAtomRef cut_copy_in_port0, cut_copy_in_port1, cut_copy_in_free0, cut_copy_in_free1; + LmnSymbolAtomRef cut_copy_out_port0, cut_copy_out_port1, cut_copy_out_free0, cut_copy_out_free1; + LmnMembraneRef cut_copy_mem0, cut_copy_mem1; + ProcessTableRef cut_atom_map0, cut_atom_map1; + LmnWord t_cut0, t_cut1, t_cut2, t_cut3; + + proc_tbl_get_by_atom(atom_map, org_port_in, &t); + trg_port_in = (LmnSymbolAtomRef)(t); + org_port_out = (LmnSymbolAtomRef)(org_in->get_link(0)); + trg_port_out = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + lmn_newlink_in_symbols(trg_port_in, 0, trg_port_out, 0); + + // cutをコピー + cut_copy_mem0 = new LmnMembrane(); + cut_copy_mem1 = new LmnMembrane(); + cut_atom_map0 = lmn_mem_copy_cells(cut_copy_mem0, cut_mem); + cut_atom_map1 = lmn_mem_copy_cells(cut_copy_mem1, cut_mem); + mem->add_child_mem(cut_copy_mem0); + mem->add_child_mem(cut_copy_mem1); + + // cut_copyのproxyアトムを用意する + proc_tbl_get_by_atom(cut_atom_map0, cut_in_port, &t_cut0); + proc_tbl_get_by_atom(cut_atom_map0, cut_in_free, &t_cut1); + cut_copy_in_port0 = (LmnSymbolAtomRef)(t_cut0); + cut_copy_in_free0 = (LmnSymbolAtomRef)(t_cut1); + proc_tbl_get_by_atom(cut_atom_map1, cut_in_port, &t_cut2); + proc_tbl_get_by_atom(cut_atom_map1, cut_in_free, &t_cut3); + cut_copy_in_port1 = (LmnSymbolAtomRef)(t_cut2); + cut_copy_in_free1 = (LmnSymbolAtomRef)(t_cut3); + + cut_copy_out_port0 = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + cut_copy_out_free0 = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + cut_copy_out_port1 = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + cut_copy_out_free1 = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + + lmn_newlink_in_symbols(cut_copy_in_port0, 0, cut_copy_out_port0, 0); + lmn_newlink_in_symbols(cut_copy_in_free0, 0, cut_copy_out_free0, 0); + lmn_newlink_in_symbols(cut_copy_in_port1, 0, cut_copy_out_port1, 0); + lmn_newlink_in_symbols(cut_copy_in_free1, 0, cut_copy_out_free1, 0); + + // portとfreeをcutでつなげる + lmn_newlink_in_symbols(cut_copy_out_port0, 1, org_port_out, 1); + lmn_newlink_in_symbols(cut_copy_out_free0, 1, free0, 0); + lmn_newlink_in_symbols(cut_copy_out_port1, 1, trg_port_out, 1); + lmn_newlink_in_symbols(cut_copy_out_free1, 1, free1, 0); + + delete cut_atom_map0; + delete cut_atom_map1; + mem->remove_mem(cut_copy_mem0); + mem->remove_mem(cut_copy_mem1); + cut_copy_mem0->remove_proxies(); + cut_copy_mem1->remove_proxies(); + mem->move_cells(cut_copy_mem0); + mem->move_cells(cut_copy_mem1); + + } else { + proc_tbl_get_by_atom(atom_map, org_in, &t); + trg_in = (LmnSymbolAtomRef)(t); + org_out = (LmnSymbolAtomRef)(org_in->get_link(0)); + trg_out = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + lmn_newlink_in_symbols(trg_in, 0, trg_out, 0); + + // cont_memをコピーする + LmnSymbolAtomRef cont_copy_in0, cont_copy_in1, cont_copy_in2; + LmnSymbolAtomRef cont_copy_out0, cont_copy_out1, cont_copy_out2; + LmnMembraneRef cont_copy_mem; + ProcessTableRef cont_atom_map; + LmnWord t_cont0, t_cont1, t_cont2; + + cont_copy_mem = new LmnMembrane(); + cont_atom_map = lmn_mem_copy_cells(cont_copy_mem, cont_mem); + mem->add_child_mem(cont_copy_mem); + + // cont_copyのproxyアトムを用意する + proc_tbl_get_by_atom(cont_atom_map, cont_in0, &t_cont0); + proc_tbl_get_by_atom(cont_atom_map, cont_in1, &t_cont1); + proc_tbl_get_by_atom(cont_atom_map, cont_in2, &t_cont2); + cont_copy_in0 = (LmnSymbolAtomRef)(t_cont0); + cont_copy_in1 = (LmnSymbolAtomRef)(t_cont1); + cont_copy_in2 = (LmnSymbolAtomRef)(t_cont2); + + cont_copy_out0 = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + cont_copy_out1 = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + cont_copy_out2 = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + + lmn_newlink_in_symbols(cont_copy_in0, 0, cont_copy_out0, 0); + lmn_newlink_in_symbols(cont_copy_in1, 0, cont_copy_out1, 0); + lmn_newlink_in_symbols(cont_copy_in2, 0, cont_copy_out2, 0); + + // orgとtrgをcontでつなげる + lmn_relink_symbols(cont_copy_out2, 1, org_out, 1); + lmn_newlink_in_symbols(cont_copy_out0, 1, org_out, 1); + lmn_newlink_in_symbols(cont_copy_out1, 1, trg_out, 1); + + delete cont_atom_map; + mem->remove_mem(cont_copy_mem); + cont_copy_mem->remove_proxies(); + mem->move_cells(cont_copy_mem); + } + mem->remove_temporary_proxies(); + })); + } + + delete atom_map; + + if (rc->has_mode(REACT_MEM_ORIENTED)) { + ((MemReactContext *)rc)->memstack_remove(cont_mem); + ((MemReactContext *)rc)->memstack_remove(cut_mem); + } + + mem->delete_mem(cont_mem); + mem->delete_mem(cut_mem); + + lmn_mem_delete_atom(mem, a1, t1); + lmn_mem_delete_atom(mem, a2, t2); + lmn_mem_delete_atom(mem, a3, t3); + lmn_mem_delete_atom(mem, a4, t4); + lmn_mem_delete_atom(mem, a5, t5); + } +} + +void mell_kill(LmnReactCxtRef rc, + LmnMembraneRef mem, + LmnAtomRef a0, LmnLinkAttr t0, + LmnAtomRef a1, LmnLinkAttr t1) +{ + // 削除対象の膜 + LmnSymbolAtomRef org_in; + LmnMembraneRef org_mem; + + // タグの膜 + LmnSymbolAtomRef tag_in; + LmnMembraneRef tag_mem; + + if (((LmnSymbolAtomRef)a0)->get_functor() != LMN_OUT_PROXY_FUNCTOR) { + fprintf(stderr, "mell.C, mell_kill: first argument must be a membrane"); + return; + } + if (((LmnSymbolAtomRef)a1)->get_functor() != LMN_OUT_PROXY_FUNCTOR) { + fprintf(stderr, "mell.C, mell_kill: second argument must be a membrane"); + return; + } + + org_in = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a0)->get_link(0)); + org_mem = LMN_PROXY_GET_MEM(org_in); + + tag_in = (LmnSymbolAtomRef)(((LmnSymbolAtomRef)a1)->get_link(0)); + tag_mem = LMN_PROXY_GET_MEM(tag_in); + { + AtomListEntryRef ent = org_mem->get_atomlist(LMN_IN_PROXY_FUNCTOR); + + if (ent) { + LmnSymbolAtomRef in, out; + LmnLinkAttr out_attr; + EACH_ATOM(in, ent, ({ + if (in == org_in) continue; + out = (LmnSymbolAtomRef)(in->get_link(0)); + out_attr = in->get_attr(0); + + LmnMembraneRef tag_copy_mem; + ProcessTableRef atom_map; + tag_copy_mem = new LmnMembrane(); + atom_map = lmn_mem_copy_cells(tag_copy_mem, tag_mem); + mem->add_child_mem(tag_copy_mem); + { + LmnSymbolAtomRef tag_copy_in, tag_copy_out, dummy; + LmnLinkAttr tag_copy_out_attr; + LmnWord t = 0; + + proc_tbl_get_by_atom(atom_map, tag_in, &t); + tag_copy_in = (LmnSymbolAtomRef)(t); + tag_copy_out = lmn_mem_newatom(mem, LMN_OUT_PROXY_FUNCTOR); + lmn_newlink_in_symbols(tag_copy_in, 0, tag_copy_out, 0); + + lmn_relink_symbols(tag_copy_out, 1, out, 1); + + delete atom_map; + mem->remove_mem(tag_copy_mem); + tag_copy_mem->remove_proxies(); + mem->move_cells(tag_copy_mem); + mem->remove_temporary_proxies(); + } + lmn_mem_delete_atom(mem, out, out_attr); + })); + } + } + + if (rc->has_mode(REACT_MEM_ORIENTED)) { + ((MemReactContext *)rc)->memstack_remove(org_mem); + ((MemReactContext *)rc)->memstack_remove(tag_mem); + } + + mem->delete_mem(org_mem); + mem->delete_mem(tag_mem); + lmn_mem_delete_atom(mem, a0, t0); + lmn_mem_delete_atom(mem, a1, t1); +} + +void init_mell(void) { + CCallback::lmn_register_c_fun("mell_copy", (void *)mell_copy, 8); + CCallback::lmn_register_c_fun("mell_kill", (void *)mell_kill, 2); +} diff --git a/src/vm/task.cpp b/src/vm/task.cpp index 64090a98c..040274c07 100644 --- a/src/vm/task.cpp +++ b/src/vm/task.cpp @@ -71,6 +71,23 @@ typedef void (*callback_5)(LmnReactCxtRef, LmnMembraneRef, LmnAtomRef, LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, LmnLinkAttr); +typedef void (*callback_6)(LmnReactCxtRef, LmnMembraneRef, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr); + +typedef void (*callback_7)(LmnReactCxtRef, LmnMembraneRef, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, + LmnLinkAttr); + +typedef void (*callback_8)(LmnReactCxtRef, LmnMembraneRef, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr, LmnAtomRef, + LmnLinkAttr, LmnAtomRef, LmnLinkAttr); + struct Vector user_system_rulesets; /* system ruleset defined by user */ /** @@ -4434,6 +4451,34 @@ bool slim::vm::interpreter::exec_command(LmnReactCxt *rc, LmnRuleRef rule, atom->get_link(3), atom->get_attr(3), atom->get_link(4), atom->get_attr(4), atom->get_link(5), atom->get_attr(5)); break; + case 7: + ((callback_6)c->get_f())( + rc, (LmnMembraneRef)rc->wt(memi), atom->get_link(1), + atom->get_attr(1), atom->get_link(2), atom->get_attr(2), + atom->get_link(3), atom->get_attr(3), atom->get_link(4), + atom->get_attr(4), atom->get_link(5), atom->get_attr(5), + atom->get_link(6), atom->get_attr(6)); + break; + case 8: + ((callback_7)c->get_f())( + rc, (LmnMembraneRef)rc->wt(memi), atom->get_link(1), + atom->get_attr(1), atom->get_link(2), atom->get_attr(2), + atom->get_link(3), atom->get_attr(3), atom->get_link(4), + atom->get_attr(4), atom->get_link(5), atom->get_attr(5), + atom->get_link(6), atom->get_attr(6), atom->get_link(7), + atom->get_attr(7)); + break; + case 9: + ((callback_8)c->get_f())( + rc, (LmnMembraneRef)rc->wt(memi), atom->get_link(1), + atom->get_attr(1), atom->get_link(2), atom->get_attr(2), + atom->get_link(3), atom->get_attr(3), atom->get_link(4), + atom->get_attr(4), atom->get_link(5), atom->get_attr(5), + atom->get_link(6), atom->get_attr(6), atom->get_link(7), + atom->get_attr(7), atom->get_link(8), atom->get_attr(8) + ); + break; + default: printf("EXTERNAL FUNCTION: too many arguments\n"); break; @@ -5434,6 +5479,40 @@ static BOOL dmem_interpret(LmnReactCxtRef rc, LmnRuleRef rule, atom->get_link(3), atom->get_attr(3), atom->get_link(4), atom->get_attr(4)); break; + case 6: + ((callback_5)c->get_f())( + rc, (LmnMembraneRef)rc->wt(memi), atom->get_link(1), + atom->get_attr(1), atom->get_link(2), atom->get_attr(2), + atom->get_link(3), atom->get_attr(3), atom->get_link(4), + atom->get_attr(4), atom->get_link(5), atom->get_attr(5)); + break; + case 7: + ((callback_6)c->get_f())( + rc, (LmnMembraneRef)rc->wt(memi), atom->get_link(1), + atom->get_attr(1), atom->get_link(2), atom->get_attr(2), + atom->get_link(3), atom->get_attr(3), atom->get_link(4), + atom->get_attr(4), atom->get_link(5), atom->get_attr(5), + atom->get_link(6), atom->get_attr(6)); + break; + case 8: + ((callback_7)c->get_f())( + rc, (LmnMembraneRef)rc->wt(memi), atom->get_link(1), + atom->get_attr(1), atom->get_link(2), atom->get_attr(2), + atom->get_link(3), atom->get_attr(3), atom->get_link(4), + atom->get_attr(4), atom->get_link(5), atom->get_attr(5), + atom->get_link(6), atom->get_attr(6), atom->get_link(7), + atom->get_attr(7)); + break; + case 9: + ((callback_8)c->get_f())( + rc, (LmnMembraneRef)rc->wt(memi), atom->get_link(1), + atom->get_attr(1), atom->get_link(2), atom->get_attr(2), + atom->get_link(3), atom->get_attr(3), atom->get_link(4), + atom->get_attr(4), atom->get_link(5), atom->get_attr(5), + atom->get_link(6), atom->get_attr(6), atom->get_link(7), + atom->get_attr(7), atom->get_link(8), atom->get_attr(8) + ); + break; default: printf("EXTERNAL FUNCTION: too many arguments\n"); break;