From 757ad37e0a926dfd4908c2ec3b8e479dbb15d248 Mon Sep 17 00:00:00 2001 From: Valk Richard Li <48872266+ValKmjolnir@users.noreply.github.com> Date: Wed, 29 Jan 2020 17:07:01 +0800 Subject: [PATCH] update --- version2.0/nasal_enum.h | 50 +-- version2.0/nasal_parse.h | 8 +- version2.0/test/final2.nas | 643 +++++++++++++++++++++++++++++++++++++ version2.0/test/scope.nas | 62 ++++ 4 files changed, 736 insertions(+), 27 deletions(-) create mode 100644 version2.0/test/final2.nas create mode 100644 version2.0/test/scope.nas diff --git a/version2.0/nasal_enum.h b/version2.0/nasal_enum.h index 7869a65..595af9b 100644 --- a/version2.0/nasal_enum.h +++ b/version2.0/nasal_enum.h @@ -92,45 +92,45 @@ void print_parse_token(int type) case __div_equal: context=" /= "; break; case __link_equal: context=" ~= "; break; - case __left_brace: context="{"; break; - case __right_brace: context="}"; break; - case __left_bracket: context="["; break; - case __right_bracket: context="]"; break; - case __left_curve: context="("; break; - case __right_curve: context=")"; break; + case __left_brace: context="{"; break; + case __right_brace: context="}"; break; + case __left_bracket: context="["; break; + case __right_bracket: context="]"; break; + case __left_curve: context="("; break; + case __right_curve: context=")"; break; - case __semi: context=";"; break; - case __comma: context=","; break; - case __colon: context=":"; break; - case __dot: context="."; break; - case __ques_mark: context="?"; break; + case __semi: context=";"; break; + case __comma: context=","; break; + case __colon: context=":"; break; + case __dot: context="."; break; + case __ques_mark: context="?"; break; case __unknown_operator: context="unknown_operator";break; case __var: context="var "; break; case __func: context="func "; break; - case __continue: context="continue"; break; - case __break: context="break"; break; - case __for: context="for"; break; - case __forindex: context="forindex"; break; + case __continue: context="continue"; break; + case __break: context="break"; break; + case __for: context="for"; break; + case __forindex: context="forindex"; break; case __foreach: context="foreach "; break; - case __while: context="while"; break; + case __while: context="while"; break; case __if: context="if "; break; case __elsif: context="elsif "; break; case __else: context="else "; break; case __return: context="return "; break; - case __nil: context="nil"; break; + case __nil: context="nil"; break; - case __id: context="identifier"; break; - case __dynamic_id: context="identifier...";break; - case __number: context="number"; break; - case __string: context="string"; break; + case __id: context="id"; break; + case __dynamic_id: context="id..."; break; + case __number: context="num"; break; + case __string: context="str"; break; case __root: context="root"; break; case __null_type: context="null_type"; break; - case __multi_id: context="identifiers"; break; + case __multi_id: context="ids"; break; case __multi_scalar: context="scalars"; break; - case __parameters: context="parameters"; break; + case __parameters: context="paras"; break; case __special_para: context="id:scalar"; break; case __defult_parameter: context="para=scalar"; break; case __vector: context="vector"; break; @@ -141,11 +141,11 @@ void print_parse_token(int type) case __call_vector: context="call_vector"; break; case __call_hash: context="call_hash"; break; case __normal_statement_block:context="block"; break; - case __definition: context="definition"; break; + case __definition: context="def"; break; case __function: context="function"; break; case __conditional: context="conditional"; break; - default: context="undefined_token";break; + default: context="undefined"; break; } std::cout<push_token(); + } else { ++error; @@ -1163,7 +1166,8 @@ abstract_syntax_tree nasal_parse::function_generate() } else this->push_token(); - parameter_list.add_children(parameter); + if(parameter.get_node_type()!=__null_type) + parameter_list.add_children(parameter); // check comma or right_curve this->get_token(); if((this_token.type!=__right_curve) && (this_token.type!=__comma)) @@ -1179,10 +1183,10 @@ abstract_syntax_tree nasal_parse::function_generate() this->push_token(); } } - function_node.add_children(parameter_list); } else this->push_token(); + function_node.add_children(parameter_list); function_node.add_children(block_generate()); return function_node; } diff --git a/version2.0/test/final2.nas b/version2.0/test/final2.nas new file mode 100644 index 0000000..4d71d3a --- /dev/null +++ b/version2.0/test/final2.nas @@ -0,0 +1,643 @@ +############################################################################### +## +## Nasal module for dual control over the multiplayer network. +## +## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org) +## This file is licensed under the GPL license version 2 or later. +## +############################################################################### +## MP properties +var lat_mpp = "position/latitude-deg"; +var lon_mpp = "position/longitude-deg"; +var alt_mpp = "position/altitude-ft"; +var heading_mpp = "orientation/true-heading-deg"; +var pitch_mpp = "orientation/pitch-deg"; +var roll_mpp = "orientation/roll-deg"; + +# Import components from the mp_broadcast module. +var Binary = mp_broadcast.Binary; +var MessageChannel = mp_broadcast.MessageChannel; + +############################################################################### +# Utility classes + +############################################################ +# Translate a property into another. +# Factor and offsets are only used for numeric values. +# src - source : property node +# dest - destination : property node +# factor - : double +# offset - : double +var Translator = {}; +Translator.new = func (src = nil, dest = nil, factor = 1, offset = 0) { + var obj = { parents : [Translator], + src : src, + dest : dest, + factor : factor, + offset : offset }; + if (obj.src == nil or obj.dest == nil) { + print("Translator["); + print(" ", debug.string(obj.src)); + print(" ", debug.string(obj.dest)); + print("]"); + fail(); + } + + return obj; +} +Translator.update = func () { + var v = me.src.getValue(); + if (is_num(v)) { + me.dest.setValue(me.factor * v + me.offset); + } else { + if (typeof(v) == "scalar") + me.dest.setValue(v); + } +} + +############################################################ +# Detects flanks on two insignals encoded in a property. +# - positive signal up/down flank +# - negative signal up/down flank +# n - source : property node +# on_positive_flank - action : func (v) +# on_negative_flank - action : func (v) +var EdgeTrigger = {}; +EdgeTrigger.new = func (n, on_positive_flank, on_negative_flank) { + var obj = { parents : [EdgeTrigger], + old : 0, + node : n, + pos_flank : on_positive_flank, + neg_flank : on_negative_flank }; + if (obj.node == nil) { + print("EdgeTrigger["); + print(" ", debug.string(obj.node)); + print("]"); + fail(); + } + return obj; +} +EdgeTrigger.update = func { + # NOTE: float MP properties get interpolated. + # This detector relies on that steady state is reached between + # flanks. + var val = me.node.getValue(); + if (!is_num(val)) return; + if (me.old == 1) { + if (val < me.old) { + me.pos_flank(0); + } + } elsif (me.old == 0) { + if (val > me.old) { + me.pos_flank(1); + } elsif (val < me.old) { + me.neg_flank(1); + } + } elsif (me.old == -1) { + if (val > me.old) { + me.neg_flank(0); + } + } + me.old = val; +} + +############################################################ +# StableTrigger: Triggers an action when a MPP property +# becomes stable (i.e. doesn't change for +# MIN_STABLE seconds). +# src - MP prop : property node +# action - action to take when the value becomes stable : [func(v)] +# An action is triggered when value has stabilized. +var StableTrigger = {}; +StableTrigger.new = func (src, action) { + var obj = { parents : [StableTrigger], + src : src, + action : action, + old : 0, + stable_since : 0, + wait : 0, + MIN_STABLE : 0.01 }; + # Error checking. + var bad = (obj.src == nil) or (action = nil); + + if (bad) { + print("StableTrigger["); + print(" ", debug.string(obj.src)); + print(" ", debug.string(obj.action)); + print("]"); + fail(); + } + + return obj; +} +StableTrigger.update = func () { + var v = me.src.getValue(); + if (!is_num(v)) return; + var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time. + + if ((me.old == v) and + ((t - me.stable_since) > me.MIN_STABLE) and (me.wait == 1)) { + # Trigger action. + me.action(v); + + me.wait = 0; + } elsif (me.old == v) { + # Wait. This is either before the signal is stable or after the action. + } else { + me.stable_since = t; + me.wait = 1; + me.old = me.src.getValue(); + } +} + +############################################################ +# Selects the most recent value of two properties. +# src1 - : property node +# src2 - : property node +# dest - : property node +# threshold - : double +var MostRecentSelector = {}; +MostRecentSelector.new = func (src1, src2, dest, threshold) { + var obj = { parents : [MostRecentSelector], + old1 : 0, + old2 : 0, + src1 : src1, + src2 : src2, + dest : dest, + thres : threshold }; + if (obj.src1 == nil or obj.src2 == nil or obj.dest == nil) { + print("MostRecentSelector["); + print(" ", debug.string(obj.src1)); + print(" ", debug.string(obj.src2)); + print(" ", debug.string(obj.dest)); + print("]"); + } + + return obj; +} +MostRecentSelector.update = func { + var v1 = me.src1.getValue(); + var v2 = me.src2.getValue(); + if (!is_num(v1) and !is_num(v2)) return; + elsif (!is_num(v1)) me.dest.setValue(v2); + elsif (!is_num(v2)) me.dest.setValue(v1); + else { + if (abs (v2 - me.old2) > me.thres) { + me.old2 = v2; + me.dest.setValue(me.old2); + } + if (abs (v1 - me.old1) > me.thres) { + me.old1 = v1; + me.dest.setValue(me.old1); + } + } +} + +############################################################ +# Adds two input properties. +# src1 - : property node +# src2 - : property node +# dest - : property node +var Adder = {}; +Adder.new = func (src1, src2, dest) { + var obj = { parents : [DeltaAccumulator], + src1 : src1, + src2 : src2, + dest : dest }; + if (obj.src1 == nil or obj.src2 == nil or obj.dest == nil) { + print("Adder["); + print(" ", debug.string(obj.src1)); + print(" ", debug.string(obj.src2)); + print(" ", debug.string(obj.dest)); + print("]"); + fail(); + } + + return obj; +} +Adder.update = func () { + var v1 = me.src1.getValue(); + var v2 = me.src2.getValue(); + if (!is_num(v1) or !is_num(v2)) return; + me.dest.setValue(v1 + v2); +} + +############################################################ +# Adds the delta of src to dest. +# src - : property node +# dest - : property node +var DeltaAdder = {}; +DeltaAdder.new = func (src, dest) { + var obj = { parents : [DeltaAdder], + old : 0, + src : src, + dest : dest }; + if (obj.src == nil or obj.dest == nil) { + print("DeltaAdder[", debug.string(obj.src), ", ", + debug.string(obj.dest), "]"); + fail(); + } + + return obj; +} +DeltaAdder.update = func () { + var v = me.src.getValue(); + if (!is_num(v)) return; + me.dest.setValue((v - me.old) + me.dest.getValue()); + me.old = v; +} + +############################################################ +# Switch encoder: Encodes upto 32 boolean properties in one +# int property. +# inputs - list of property nodes +# dest - where the bitmask is stored : property node +var SwitchEncoder = {}; +SwitchEncoder.new = func (inputs, dest) { + var obj = { parents : [SwitchEncoder], + inputs : inputs, + dest : dest }; + # Error checking. + var bad = (obj.dest == nil); + foreach (var i; inputs) { + if (i == nil) { bad = 1; } + } + + if (bad) { + print("SwitchEncoder["); + foreach (var i; inputs) { + print(" ", debug.string(i)); + } + print(" ", debug.string(obj.dest)); + print("]"); + fail(); + } + + return obj; +} +SwitchEncoder.update = func () { + var v = 0; + var b = 1; + forindex (var i; me.inputs) { + if (me.inputs[i].getBoolValue()) { + v = v + b; + } + b *= 2; + } + me.dest.setIntValue(v); +} + +############################################################ +# Switch decoder: Decodes a bitmask in an int property. +# src - : property node +# actions - list of actions : [func(b)] +# Actions are triggered when their input bit change. +# Due to interpolation the decoder needs to wait for a +# stable input value. +var SwitchDecoder = {}; +SwitchDecoder.new = func (src, actions) { + var obj = { parents : [SwitchDecoder], + wait : 0, + old : 0, + old_stable : 0, + stable_since : 0, + reset : 1, + src : src, + actions : actions, + MIN_STABLE : 0.1 }; + # Error checking. + var bad = (obj.src == nil); + foreach (var a; obj.actions) { + if (a == nil) { bad = 1; } + } + + if (bad) { + print("SwitchDecoder["); + print(" ", debug.string(obj.src)); + foreach (var a; obj.actions) { + print(" ", debug.string(a)); + } + print("]"); + fail(); + } + + return obj; +} +SwitchDecoder.update = func () { + var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time. + var v = me.src.getValue(); + if (!is_num(v)) return; + + if ((me.old == v) and ((t - me.stable_since) > me.MIN_STABLE) and + (me.wait == 1)) { + var ov = me.old_stable; +# Use this to improve. +# here's the boring version: var bittest = func(u, b) { while (b) { u = int(u / 2); b -= 1; } u != int(u / 2) * 2; } + forindex (var i; me.actions) { + var m = math.mod(v, 2); + var om = math.mod(ov, 2); + if ((m != om or me.reset)) { me.actions[i](m?1:0); } + v = (v - m)/2; + ov = (ov - om)/2; + } + me.old_stable = me.src.getValue(); + me.wait = 0; + me.reset = 0; + } elsif (me.old == v) { + # Wait. This is either before the bitmask is stable or after + # it has been processed. + } else { + me.stable_since = t; + me.wait = 1; + me.old = me.src.getValue(); + } +} + +############################################################ +# Time division multiplexing encoder: Transmits a list of +# properties over a MP enabled string property. +# inputs - input properties : [property node] +# dest - MP string prop : property node +# Note: TDM can have high latency so it is best used for +# non-time critical properties. +var TDMEncoder = {}; +TDMEncoder.new = func (inputs, dest) { + var obj = { parents : [TDMEncoder], + inputs : inputs, + channel : MessageChannel.new(dest, + func (msg) { + print("This should not happen!"); + }), + MIN_INT : 0.25, + last_time : 0, + next_item : 0, + old : [] }; + # Error checking. + var bad = (dest == nil) or (obj.channel == nil); + foreach (var i; inputs) { + if (i == nil) { bad = 1; } + } + + if (bad) { + print("TDMEncoder["); + foreach (var i; inputs) { + print(" ", debug.string(i)); + } + print(" ", debug.string(dest)); + print("]"); + } + + setsize(obj.old, size(obj.inputs)); + + return obj; +} +TDMEncoder.update = func () { + var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time. + if (t > me.last_time + me.MIN_INT) { + var n = size(me.inputs); + while (1) { + var v = me.inputs[me.next_item].getValue(); + + if ((n <= 0) or (me.old[me.next_item] != v)) { + # Set the MP properties to send the next item. + me.channel.send(Binary.encodeByte(me.next_item) ~ + Binary.encodeDouble(v)); + + me.old[me.next_item] = v; + + me.last_time = t; + me.next_item += 1; + if (me.next_item >= size(me.inputs)) { me.next_item = 0; } + return; + } else { + # Search for changed property. + n -= 1; + me.next_item += 1; + if (me.next_item >= size(me.inputs)) { me.next_item = 0; } + } + } + } +} + +############################################################ +# Time division multiplexing decoder: Receives a list of +# properties over a MP enabled string property. +# src - MP string prop : property node +# actions - list of actions : [func(v)] +# An action is triggered when its value is received. +# Note: TDM can have high latency so it is best used for +# non-time critical properties. +var TDMDecoder = {}; +TDMDecoder.new = func (src, actions) { + var obj = { parents : [TDMDecoder], + actions : actions }; + obj.channel = MessageChannel.new(src, + func (msg) { + obj.process(msg); + }); + + # Error checking. + var bad = (src == nil) or (obj.channel == nil); + foreach (var a; actions) { + if (a == nil) { bad = 1; } + } + + if (bad) { + print("TDMDecoder["); + print(" ", debug.string(src)); + foreach (var a; actions) { + print(" ", debug.string(a)); + } + print("]"); + fail(); + } + + return obj; +} +TDMDecoder.process = func (msg) { + var v1 = Binary.decodeByte(msg); + var v2 = Binary.decodeDouble(substr(msg, 1)); + # Trigger action. + me.actions[v1](v2); +} +TDMDecoder.update = func { + me.channel.update(); +} + +############################################################################### +# Internal utility functions + +var is_num = func (v) { + return num(v) != nil; +} + +# fail causes a Nasal runtime error so we get a backtrace. +var fail = func { + error_detected_in_calling_context(); +} + +############################################################################### + +############################################################################### +# Copilot selection dialog. +# +# Usage: dual_control_tools.copilot_dialog.show(); +# +var COPILOT_DLG = 0; +var copilot_dialog = {}; +############################################################ +copilot_dialog.init = func (copilot_type, x = nil, y = nil) { + me.x = x; + me.y = y; + me.bg = [0, 0, 0, 0.3]; # background color + me.fg = [[1.0, 1.0, 1.0, 1.0]]; + # + # "private" + if (contains(aircraft_dual_control, "copilot_view")) { + me.title = "Pilot selection"; + } else { + me.title = "Copilot selection"; + } + me.basenode = props.globals.getNode("sim/remote", 1); + me.dialog = nil; + me.namenode = props.Node.new({"dialog-name" : me.title }); + me.listeners = []; + me.copilot_type = copilot_type; +} +############################################################ +copilot_dialog.create = func { + if (me.dialog != nil) + me.close(); + + me.dialog = gui.Widget.new(); + me.dialog.set("name", me.title); + if (me.x != nil) + me.dialog.set("x", me.x); + if (me.y != nil) + me.dialog.set("y", me.y); + + me.dialog.set("layout", "vbox"); + me.dialog.set("default-padding", 0); + var titlebar = me.dialog.addChild("group"); + titlebar.set("layout", "hbox"); + titlebar.addChild("empty").set("stretch", 1); + if (contains(aircraft_dual_control, "copilot_view")) { + titlebar.addChild("text").set("label", "Book your flight"); + } else { + titlebar.addChild("text").set("label", "Passengers online"); + } + var w = titlebar.addChild("button"); + w.set("pref-width", 16); + w.set("pref-height", 16); + w.set("legend", ""); + w.set("default", 0); + w.set("key", "esc"); + w.setBinding("nasal", "dual_control_tools.copilot_dialog.destroy(); "); + w.setBinding("dialog-close"); + me.dialog.addChild("hrule"); + + var content = me.dialog.addChild("group"); + content.set("layout", "vbox"); + content.set("halign", "center"); + content.set("default-padding", 5); + + # Generate the dialog contents. + me.players = me.find_copilot_players(); + var i = 0; + var tmpbase = me.basenode.getNode("dialog", 1); + var selected = me.basenode.getNode("pilot-callsign").getValue(); + foreach (var p; me.players) { + var tmp = tmpbase.getNode("b[" ~ i ~ "]", 1); + tmp.setBoolValue(streq(selected, p)); + var w = content.addChild("checkbox"); + w.node.setValues({"label" : p, + "halign" : "left", + "property" : tmp.getPath()}); + w.setBinding + ("nasal", + "dual_control_tools.copilot_dialog.select_action(" ~ i ~ ");"); + i = i + 1; + } + me.dialog.addChild("hrule"); + + # Display the dialog. + fgcommand("dialog-new", me.dialog.prop()); + fgcommand("dialog-show", me.namenode); +} +############################################################ +copilot_dialog.close = func { + fgcommand("dialog-close", me.namenode); +} +############################################################ +copilot_dialog.destroy = func { + COPILOT_DLG = 0; + me.close(); + foreach(var l; me.listeners) + removelistener(l); + delete(gui.dialog, "\"" ~ me.title ~ "\""); +} +############################################################ +copilot_dialog.show = func (copilot_type) { +# print("Showing MPCopilots dialog!"); + if (!COPILOT_DLG) { + COPILOT_DLG = int(getprop("/sim/time/elapsed-sec")); + me.init(copilot_type); + me.create(); + me._update_(COPILOT_DLG); + } +} +############################################################ +copilot_dialog._redraw_ = func { + if (me.dialog != nil) { + me.close(); + me.create(); + } +} +############################################################ +copilot_dialog._update_ = func (id) { + if (COPILOT_DLG != id) return; + me._redraw_(); + settimer(func { me._update_(id); }, 4.1); +} +############################################################ +copilot_dialog.select_action = func (n) { + var selected = me.basenode.getNode("pilot-callsign").getValue(); + var bs = me.basenode.getNode("dialog").getChildren(); + # Assumption: There are two true b:s or none. The one not matching selected + # is the new selection. + var i = 0; + me.basenode.getNode("pilot-callsign").setValue(""); + foreach (var b; bs) { + if (!b.getValue() and (i == n)) { + b.setValue(1); + me.basenode.getNode("pilot-callsign").setValue(me.players[i]); + } else { + b.setValue(0); + } + i = i + 1; + } + dual_control.main.reset(); + me._redraw_(); +} +############################################################ +# Return a list containing all nearby copilot players of the right type. +copilot_dialog.find_copilot_players = func { + var mpplayers = + props.globals.getNode("ai/models").getChildren("multiplayer"); + + var res = []; + foreach (var pilot; mpplayers) { + if ((pilot.getNode("valid") != nil) and + (pilot.getNode("valid").getValue()) and + (pilot.getNode("sim/model/path") != nil)) { + var type = pilot.getNode("sim/model/path").getValue(); + + if (type == me.copilot_type) { + append(res, pilot.getNode("callsign").getValue()); + } + } + } +# debug.dump(res); + return res; +} +############################################################################### diff --git a/version2.0/test/scope.nas b/version2.0/test/scope.nas new file mode 100644 index 0000000..a8a1fab --- /dev/null +++ b/version2.0/test/scope.nas @@ -0,0 +1,62 @@ +var global_value=0; +var global_hash= +{ + var1:1, + var2:2, + var3:func(){return me.var2;} +}; +print(global_value); +print(global_hash.var3()); + +var func1=func() +{ + global_value=1; + print(global_value); + var closure_value=1; + var temp_value=1; + print(temp_value); + return func{return closure_value;}; +} + +var func2=func() +{ + for(var temp_value=0;temp_value<100;temp_value+=1) + { + if(temp_value<10) + print(temp_value,"< 10"); + elsif(10<=temp_value and temp_value<50) + print(temp_value,"< 50"); + 10=temp_value; + } + return; +} + +var func3=func() +{ + var fake_closure_value=1; + return func() + { + var fake_closure_value=2; + return fake_closure_value; + }; +} + +func1()(); +func2(); +func3()(); + +if(!global_value) +{ + var temp_value=1; + if(temp_value) + { + var temp_value=2; + if(temp_value>=1) + { + var temp_value=3; + print(temp_value); + } + print(temp_value); + } + print(temp_value); +} \ No newline at end of file