Clojure中使用instaparse后如何按键检索元素?

时间:2018-12-23 10:10:05

标签: clojure

我正在尝试为学校项目制作编译器。我是clojure的初学者。我已经完成了一个简单的程序( interpreting-lang-if ),该程序可以使用instaparse解析字符串并返回如下所示的向量:

[:LangIF [:before_if "676767; "] [:condition_expression "0"] 
[:statements_OK "1; 2;"] [:statements_NOK "3+4;"] [:after_if ""]]

如何从列表中获取“ before_if”元素?

我试图理解get函数,但在使用该函数时必须有所了解。

以下是一些代码:

(prn (interpreting-lang-if "676767; if (0) {1; 2;}else{3+4;};"))
(get (interpreting-lang-if "676767; if (0) {1; 2;}else{3+4;};") :before_if)
(get :before_if (interpreting-lang-if "676767; if (0) {1; 2;}else{3+4;};"))

预期输出应为“ 676767” 而不是 nil

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

如果您不知道物品的确切位置:

(->> [:LangIF [:before_if "676767; "] [:condition_expression "0"]
      [:statements_OK "1; 2;"] [:statements_NOK "3+4;"] [:after_if ""]]
     (tree-seq vector? rest)
     (filter vector?)
     (filter (comp (partial = :before_if) first))
     (first)
     (second))

或者,如果您愿意并且想要使用幽灵:

(let [A [:LangIF [:before_if "676767; "] [:condition_expression "0"]
       [:statements_OK "1; 2;"] [:statements_NOK "3+4;"] [:after_if ""]]]
    (select [1 1] A))

或简单地获取:

(let [A [:LangIF [:before_if "676767; "] [:condition_expression "0"]
       [:statements_OK "1; 2;"] [:statements_NOK "3+4;"] [:after_if ""]]]
    (get (get A 1) 1))

答案 1 :(得分:1)

我发现拉链对于Instaparse AST很有用,尤其是当您需要找到一个特定节点然后找到另一个相对于它的节点时。这是一个搜索节点的函数,以找到与谓词匹配的函数:

 public function execute(Input $input, Output $output)
 {
    $tele_data = Telesales::field('*')->where([['create_time','<',time()-48*3600],['customer_label','in',[2,6,7]],['virtual_sale','=','0']])->whereRaw('phone is not null')->select()->toArray();

    foreach($tele_data as $key=>$value) {
        static::pushTeleToIdc($value);
    }
}


private static function pushTeleToIdc($data = []) {

    $res = Telesales::where('id',$value['id'])->update(['virtual_sale'=>'1']);
    if(!$res) {
        return;
    }
    $url = config('idc.tele_url');
    $key = config('idc.tele_key');
    $channel = config('idc.tele_channel');
    $time = time();
    $sign = md5($key.$channel.$time);
    $urls = $url."?channel=".$channel."&sign=".$sign."&time=".$time;
    $require_params = config('idc.require_params');
    foreach($require_params as $key=>$value) {
        if(array_key_exists($key,$data) && !empty($data[$key])) {
            $d[$key] = $data[$key];
        }else{
            $d[$key] = empty($value)?'':$value[array_rand($value,1)];
        }
    }

    $d['register_time'] = $d['create_time'];

    $res =  post_url($urls,$d);
    $result = json_decode($res,true);
    if (isset($result['code']) && $result['code'] != 0){
        Log::init(['single'=>'tpushidc'])->error($res);
    }
}

要在您的AST中找到(require '[clojure.zip :as zip]) (defn zip-to ([loc pred direction] (loop [loc loc] (if (and loc (not (zip/end? loc))) (if (pred (zip/node loc)) loc (recur (direction loc))) loc))))

:before_if

答案 2 :(得分:1)

您可以使用Tupelo Forest库轻松地操作类似树的数据结构。这是a live example of your problem

(dotest
  (with-forest (new-forest)
    (let [data-hiccup  [:LangIF
                        [:before_if "676767; "]
                        [:condition_expression "0"]
                        [:statements_OK "1; 2;"]
                        [:statements_NOK "3+4;"]
                        [:after_if ""]]

          root-hid     (add-tree-hiccup data-hiccup)
          before-hid   (find-hid root-hid [:LangIF :before_if])
          before-node  (hid->node before-hid)
          before-value (grab :value before-node)]

      (is= before-node {:tupelo.forest/khids [], :tag :before_if, :value "676767; "})
      (is= before-value "676767; "))))

before-hid是指向所需节点的指针,我们可以通过从根节点指定所需路径[:LangIF :before_if]来找到。然后,我们可以将指针转换为整个节点,并从该节点提取:value。许多进一步的操作是可能的。参见the docsmore examples